Release v0.51.346 — Release LJ (PWA notification controls #3229) (#3897)
* Add PWA notification controls (#3229, #3196)
Rebased onto fresh master (#3229 was 281 commits behind). Routes browser
notifications through the service worker (reg.showNotification) with a direct
Notification fallback, threads the originating session deep link/tag into the
payload, and adds Enable/Send-test/permission-status controls in Settings.
notificationclick prefers an already-open target-session tab before opening a
new window. Added the 6 new i18n keys to the Polish (pl) locale block, which
the original PR missed.
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
* Apply Opus review fixes to #3229 PWA notifications
- MUST-FIX: _showPwaNotification used navigator.serviceWorker.ready, which
never settles when no SW registration ever activates (reverse-proxy MIME
mishap, SW disabled) — every notification was silently dropped, a regression
vs master. Switch to getRegistration() raced against a 2s timeout, falling
back to new Notification().
- SHOULD-FIX: notificationclick matched client.url === targetUrl exactly, but
_sessionUrlForSid copies the current query/hash into the deep link, so an
already-open session tab missed the match and spawned a duplicate window.
Compare pathnames instead.
- SHOULD-FIX: "Send test" with permission denied was a silent no-op — now
surfaces the notifications_denied toast on the force path.
- SHOULD-FIX: permission-status span went stale after granting via the button
— refresh it in requestNotificationPermission().then.
- Consistency: the request-permission grant branch now has the same
new Notification fallback as the granted branch.
- Update test_pwa_notification_controls.py to assert the pathname match.
* Stamp v0.51.346 — Release LJ (PWA notification controls #3229/#3196)
---------
Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
2026-06-09 22:54:21 +00:00
|
|
|
"""Regression coverage for PWA-backed browser notifications (#3196)."""
|
|
|
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
MESSAGES_JS = (ROOT / "static" / "messages.js").read_text(encoding="utf-8")
|
|
|
|
|
SW_JS = (ROOT / "static" / "sw.js").read_text(encoding="utf-8")
|
|
|
|
|
INDEX_HTML = (ROOT / "static" / "index.html").read_text(encoding="utf-8")
|
|
|
|
|
PANELS_JS = (ROOT / "static" / "panels.js").read_text(encoding="utf-8")
|
|
|
|
|
I18N_JS = (ROOT / "static" / "i18n.js").read_text(encoding="utf-8")
|
|
|
|
|
CHANGELOG = (ROOT / "CHANGELOG.md").read_text(encoding="utf-8")
|
|
|
|
|
|
2026-06-23 21:10:03 +00:00
|
|
|
DESKTOP_BACKGROUND_NOTIFICATION_NAMES = (
|
|
|
|
|
"_desktopBackgroundedForNotifications",
|
|
|
|
|
"__hermesSetBackgrounded",
|
|
|
|
|
"_isBackgroundedForBrowserNotification",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _source_between(start_marker: str, end_marker: str) -> str:
|
|
|
|
|
start = MESSAGES_JS.index(start_marker)
|
|
|
|
|
end = MESSAGES_JS.index(end_marker, start)
|
|
|
|
|
return MESSAGES_JS[start:end]
|
|
|
|
|
|
Release v0.51.346 — Release LJ (PWA notification controls #3229) (#3897)
* Add PWA notification controls (#3229, #3196)
Rebased onto fresh master (#3229 was 281 commits behind). Routes browser
notifications through the service worker (reg.showNotification) with a direct
Notification fallback, threads the originating session deep link/tag into the
payload, and adds Enable/Send-test/permission-status controls in Settings.
notificationclick prefers an already-open target-session tab before opening a
new window. Added the 6 new i18n keys to the Polish (pl) locale block, which
the original PR missed.
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
* Apply Opus review fixes to #3229 PWA notifications
- MUST-FIX: _showPwaNotification used navigator.serviceWorker.ready, which
never settles when no SW registration ever activates (reverse-proxy MIME
mishap, SW disabled) — every notification was silently dropped, a regression
vs master. Switch to getRegistration() raced against a 2s timeout, falling
back to new Notification().
- SHOULD-FIX: notificationclick matched client.url === targetUrl exactly, but
_sessionUrlForSid copies the current query/hash into the deep link, so an
already-open session tab missed the match and spawned a duplicate window.
Compare pathnames instead.
- SHOULD-FIX: "Send test" with permission denied was a silent no-op — now
surfaces the notifications_denied toast on the force path.
- SHOULD-FIX: permission-status span went stale after granting via the button
— refresh it in requestNotificationPermission().then.
- Consistency: the request-permission grant branch now has the same
new Notification fallback as the granted branch.
- Update test_pwa_notification_controls.py to assert the pathname match.
* Stamp v0.51.346 — Release LJ (PWA notification controls #3229/#3196)
---------
Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
2026-06-09 22:54:21 +00:00
|
|
|
|
|
|
|
|
def test_browser_notifications_use_service_worker_when_available():
|
|
|
|
|
assert "function _showPwaNotification" in MESSAGES_JS
|
|
|
|
|
assert "navigator.serviceWorker.ready" in MESSAGES_JS
|
|
|
|
|
assert "reg.showNotification" in MESSAGES_JS
|
|
|
|
|
assert "new Notification" in MESSAGES_JS
|
|
|
|
|
assert "function sendBrowserNotification" in MESSAGES_JS
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_notification_payload_uses_completion_session_when_provided():
|
|
|
|
|
assert "function _notificationOptions" in MESSAGES_JS
|
|
|
|
|
assert "const sid=(options&&options.sid)||(S&&S.session&&S.session.session_id);" in MESSAGES_JS
|
|
|
|
|
assert "_sessionUrlForSid(sid)" in MESSAGES_JS
|
|
|
|
|
assert "data:{url}" in MESSAGES_JS
|
|
|
|
|
assert "tag:sid?`hermes-${sid}`" in MESSAGES_JS
|
2026-06-27 03:46:52 +00:00
|
|
|
assert "function _completionNotificationPreviewText" in MESSAGES_JS
|
|
|
|
|
assert "_completionNotificationPreviewText(lastAsst," in MESSAGES_JS
|
|
|
|
|
assert "sendBrowserNotification('Response complete',_completionPreview||'Task finished',{forceHidden:_wasEverBackgrounded,sid:activeSid})" in MESSAGES_JS
|
|
|
|
|
assert "assistantText?assistantText.slice(0,100)" not in MESSAGES_JS
|
Release v0.51.346 — Release LJ (PWA notification controls #3229) (#3897)
* Add PWA notification controls (#3229, #3196)
Rebased onto fresh master (#3229 was 281 commits behind). Routes browser
notifications through the service worker (reg.showNotification) with a direct
Notification fallback, threads the originating session deep link/tag into the
payload, and adds Enable/Send-test/permission-status controls in Settings.
notificationclick prefers an already-open target-session tab before opening a
new window. Added the 6 new i18n keys to the Polish (pl) locale block, which
the original PR missed.
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
* Apply Opus review fixes to #3229 PWA notifications
- MUST-FIX: _showPwaNotification used navigator.serviceWorker.ready, which
never settles when no SW registration ever activates (reverse-proxy MIME
mishap, SW disabled) — every notification was silently dropped, a regression
vs master. Switch to getRegistration() raced against a 2s timeout, falling
back to new Notification().
- SHOULD-FIX: notificationclick matched client.url === targetUrl exactly, but
_sessionUrlForSid copies the current query/hash into the deep link, so an
already-open session tab missed the match and spawned a duplicate window.
Compare pathnames instead.
- SHOULD-FIX: "Send test" with permission denied was a silent no-op — now
surfaces the notifications_denied toast on the force path.
- SHOULD-FIX: permission-status span went stale after granting via the button
— refresh it in requestNotificationPermission().then.
- Consistency: the request-permission grant branch now has the same
new Notification fallback as the granted branch.
- Update test_pwa_notification_controls.py to assert the pathname match.
* Stamp v0.51.346 — Release LJ (PWA notification controls #3229/#3196)
---------
Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
2026-06-09 22:54:21 +00:00
|
|
|
assert "sendBrowserNotification('Approval required',d.description||'Tool approval needed',{sid:activeSid})" in MESSAGES_JS
|
|
|
|
|
assert "sendBrowserNotification('Clarification needed',d.question||'Tool clarification needed',{sid:activeSid})" in MESSAGES_JS
|
|
|
|
|
|
|
|
|
|
|
2026-06-27 03:46:52 +00:00
|
|
|
def test_completion_notification_preview_uses_settled_message_not_live_prefix():
|
|
|
|
|
"""Background completion preview must not slice the live-stream accumulator."""
|
|
|
|
|
assert "function _completionNotificationPreviewText" in MESSAGES_JS
|
2026-06-27 04:18:15 +00:00
|
|
|
assert "String(msgContent(lastAssistantMessage)||'').trim()" in MESSAGES_JS
|
2026-06-27 03:46:52 +00:00
|
|
|
assert "_assistantTurnAnchorSettledFinalAnswer" in MESSAGES_JS
|
|
|
|
|
done_block = _source_between("source.addEventListener('done'", "source.addEventListener('stream_end'")
|
|
|
|
|
assert "let lastAsst=null;" in done_block
|
|
|
|
|
assert "d.session.messages" in done_block
|
|
|
|
|
assert "liveDisplayText:typeof _streamDisplay==='function'?_streamDisplay():assistantText" in done_block
|
|
|
|
|
|
|
|
|
|
|
2026-06-19 23:48:42 +00:00
|
|
|
def test_completion_notification_fires_when_tab_was_hidden_during_stream():
|
|
|
|
|
"""#4416: a throttled background-tab SSE delivers `done` late (after the user
|
|
|
|
|
returns, document.hidden=false), which silently dropped the completion
|
|
|
|
|
notification. The done handler now passes forceHidden based on whether the
|
|
|
|
|
tab was hidden at ANY point during the stream, and sendBrowserNotification
|
|
|
|
|
bypasses ONLY the live visibility gate (not the user's enabled setting) on
|
|
|
|
|
forceHidden — so a backgrounded stream notifies, a watched one stays silent."""
|
|
|
|
|
# The per-stream hidden tracker exists and is wired at attach + done.
|
|
|
|
|
assert "_STREAM_WAS_HIDDEN" in MESSAGES_JS
|
|
|
|
|
assert "function _bindStreamHiddenTracker" in MESSAGES_JS
|
2026-06-19 23:54:23 +00:00
|
|
|
# Entries are stream-owned ({streamId, wasHidden}) so a stale entry from a
|
|
|
|
|
# non-`done` terminal path can't be mis-attributed to a later same-sid stream.
|
2026-06-23 21:10:03 +00:00
|
|
|
assert "function _shouldForceCompletionNotification(sid, streamId){" in MESSAGES_JS
|
|
|
|
|
assert "return wasHidden||wasBackgrounded;" in MESSAGES_JS
|
2026-06-19 23:54:23 +00:00
|
|
|
assert "function _clearStreamHidden" in MESSAGES_JS
|
2026-06-23 21:10:03 +00:00
|
|
|
assert "function _clearStreamNotificationBackground" in MESSAGES_JS
|
|
|
|
|
# Done-path cleanup lives inside _shouldForceCompletionNotification(); the
|
|
|
|
|
# activeSid call sites are the non-done terminal paths.
|
|
|
|
|
assert "_clearStreamHidden(sid, streamId);" in MESSAGES_JS
|
|
|
|
|
assert "_clearStreamNotificationBackground(sid, streamId);" in MESSAGES_JS
|
|
|
|
|
assert MESSAGES_JS.count("_clearStreamHidden(activeSid, streamId)") >= 3
|
|
|
|
|
assert MESSAGES_JS.count("_clearStreamNotificationBackground(activeSid, streamId)") >= 3
|
2026-06-19 23:48:42 +00:00
|
|
|
# sendBrowserNotification honors forceHidden but still respects the
|
|
|
|
|
# notifications-enabled setting (forceHidden is NOT the test-button force).
|
|
|
|
|
assert "const forceHidden=!!(options&&options.forceHidden);" in MESSAGES_JS
|
|
|
|
|
assert "if(!force&&!window._notificationsEnabled) return;" in MESSAGES_JS
|
2026-06-23 21:10:03 +00:00
|
|
|
assert "function _isBackgroundedForBrowserNotification(){" in MESSAGES_JS
|
|
|
|
|
assert "window.__hermesSetBackgrounded=(value)=>{" in MESSAGES_JS
|
|
|
|
|
assert "if(!force&&!forceHidden&&!_isBackgroundedForBrowserNotification()) return;" in MESSAGES_JS
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_desktop_background_notification_signal_stays_out_of_stream_visibility():
|
|
|
|
|
stream_tracker = _source_between(
|
|
|
|
|
"const LIVE_STREAMS={};",
|
|
|
|
|
"function closeLiveStream(sessionId, streamId, source){",
|
|
|
|
|
)
|
|
|
|
|
deferred_recovery = _source_between(
|
|
|
|
|
"function _reattachOrRestoreAfterDeferredStreamError(source){",
|
|
|
|
|
" // Bug A fix (#631):",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for name in DESKTOP_BACKGROUND_NOTIFICATION_NAMES:
|
|
|
|
|
assert name not in stream_tracker
|
|
|
|
|
assert name not in deferred_recovery
|
2026-06-19 23:48:42 +00:00
|
|
|
|
|
|
|
|
|
Release v0.51.346 — Release LJ (PWA notification controls #3229) (#3897)
* Add PWA notification controls (#3229, #3196)
Rebased onto fresh master (#3229 was 281 commits behind). Routes browser
notifications through the service worker (reg.showNotification) with a direct
Notification fallback, threads the originating session deep link/tag into the
payload, and adds Enable/Send-test/permission-status controls in Settings.
notificationclick prefers an already-open target-session tab before opening a
new window. Added the 6 new i18n keys to the Polish (pl) locale block, which
the original PR missed.
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
* Apply Opus review fixes to #3229 PWA notifications
- MUST-FIX: _showPwaNotification used navigator.serviceWorker.ready, which
never settles when no SW registration ever activates (reverse-proxy MIME
mishap, SW disabled) — every notification was silently dropped, a regression
vs master. Switch to getRegistration() raced against a 2s timeout, falling
back to new Notification().
- SHOULD-FIX: notificationclick matched client.url === targetUrl exactly, but
_sessionUrlForSid copies the current query/hash into the deep link, so an
already-open session tab missed the match and spawned a duplicate window.
Compare pathnames instead.
- SHOULD-FIX: "Send test" with permission denied was a silent no-op — now
surfaces the notifications_denied toast on the force path.
- SHOULD-FIX: permission-status span went stale after granting via the button
— refresh it in requestNotificationPermission().then.
- Consistency: the request-permission grant branch now has the same
new Notification fallback as the granted branch.
- Update test_pwa_notification_controls.py to assert the pathname match.
* Stamp v0.51.346 — Release LJ (PWA notification controls #3229/#3196)
---------
Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
2026-06-09 22:54:21 +00:00
|
|
|
def test_service_worker_handles_notification_clicks_without_hijacking_other_sessions():
|
|
|
|
|
assert "notificationclick" in SW_JS
|
|
|
|
|
assert "event.notification.close()" in SW_JS
|
|
|
|
|
assert "clients.matchAll" in SW_JS
|
|
|
|
|
assert "clients.openWindow" in SW_JS
|
|
|
|
|
# Match the open tab on pathname, not the full href (query/hash differ).
|
|
|
|
|
assert "samePath(client.url)" in SW_JS
|
|
|
|
|
assert "new URL(clientUrl).pathname === targetPath" in SW_JS
|
|
|
|
|
assert "targetClient.focus()" in SW_JS
|
|
|
|
|
exact_idx = SW_JS.index("targetClient.focus()")
|
|
|
|
|
open_idx = SW_JS.index("self.clients.openWindow(targetUrl)")
|
|
|
|
|
navigate_idx = SW_JS.index("focusableClient.navigate(targetUrl)")
|
|
|
|
|
assert exact_idx < open_idx < navigate_idx
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_settings_expose_permission_and_test_controls():
|
|
|
|
|
assert "notificationPermissionStatus" in INDEX_HTML
|
2026-06-15 20:42:46 +00:00
|
|
|
assert 'id="notificationPermissionButtonWrap"' in INDEX_HTML
|
|
|
|
|
assert 'id="notificationPermissionButton"' in INDEX_HTML
|
Release v0.51.346 — Release LJ (PWA notification controls #3229) (#3897)
* Add PWA notification controls (#3229, #3196)
Rebased onto fresh master (#3229 was 281 commits behind). Routes browser
notifications through the service worker (reg.showNotification) with a direct
Notification fallback, threads the originating session deep link/tag into the
payload, and adds Enable/Send-test/permission-status controls in Settings.
notificationclick prefers an already-open target-session tab before opening a
new window. Added the 6 new i18n keys to the Polish (pl) locale block, which
the original PR missed.
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
* Apply Opus review fixes to #3229 PWA notifications
- MUST-FIX: _showPwaNotification used navigator.serviceWorker.ready, which
never settles when no SW registration ever activates (reverse-proxy MIME
mishap, SW disabled) — every notification was silently dropped, a regression
vs master. Switch to getRegistration() raced against a 2s timeout, falling
back to new Notification().
- SHOULD-FIX: notificationclick matched client.url === targetUrl exactly, but
_sessionUrlForSid copies the current query/hash into the deep link, so an
already-open session tab missed the match and spawned a duplicate window.
Compare pathnames instead.
- SHOULD-FIX: "Send test" with permission denied was a silent no-op — now
surfaces the notifications_denied toast on the force path.
- SHOULD-FIX: permission-status span went stale after granting via the button
— refresh it in requestNotificationPermission().then.
- Consistency: the request-permission grant branch now has the same
new Notification fallback as the granted branch.
- Update test_pwa_notification_controls.py to assert the pathname match.
* Stamp v0.51.346 — Release LJ (PWA notification controls #3229/#3196)
---------
Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
2026-06-09 22:54:21 +00:00
|
|
|
assert "requestNotificationPermission()" in INDEX_HTML
|
|
|
|
|
assert "sendBrowserNotification('Hermes test'" in INDEX_HTML
|
|
|
|
|
assert "{force:true}" in INDEX_HTML
|
|
|
|
|
assert "function updateNotificationPermissionStatus" in PANELS_JS
|
2026-06-15 20:42:46 +00:00
|
|
|
assert "const btn=$('notificationPermissionButton');" in PANELS_JS
|
|
|
|
|
assert "const btnWrap=$('notificationPermissionButtonWrap');" in PANELS_JS
|
|
|
|
|
assert "btn.disabled=granted;" in PANELS_JS
|
|
|
|
|
assert "btn.title=granted?'':label;" in PANELS_JS
|
|
|
|
|
assert "if(btnWrap) btnWrap.title=label;" in PANELS_JS
|
Release v0.51.346 — Release LJ (PWA notification controls #3229) (#3897)
* Add PWA notification controls (#3229, #3196)
Rebased onto fresh master (#3229 was 281 commits behind). Routes browser
notifications through the service worker (reg.showNotification) with a direct
Notification fallback, threads the originating session deep link/tag into the
payload, and adds Enable/Send-test/permission-status controls in Settings.
notificationclick prefers an already-open target-session tab before opening a
new window. Added the 6 new i18n keys to the Polish (pl) locale block, which
the original PR missed.
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
* Apply Opus review fixes to #3229 PWA notifications
- MUST-FIX: _showPwaNotification used navigator.serviceWorker.ready, which
never settles when no SW registration ever activates (reverse-proxy MIME
mishap, SW disabled) — every notification was silently dropped, a regression
vs master. Switch to getRegistration() raced against a 2s timeout, falling
back to new Notification().
- SHOULD-FIX: notificationclick matched client.url === targetUrl exactly, but
_sessionUrlForSid copies the current query/hash into the deep link, so an
already-open session tab missed the match and spawned a duplicate window.
Compare pathnames instead.
- SHOULD-FIX: "Send test" with permission denied was a silent no-op — now
surfaces the notifications_denied toast on the force path.
- SHOULD-FIX: permission-status span went stale after granting via the button
— refresh it in requestNotificationPermission().then.
- Consistency: the request-permission grant branch now has the same
new Notification fallback as the granted branch.
- Update test_pwa_notification_controls.py to assert the pathname match.
* Stamp v0.51.346 — Release LJ (PWA notification controls #3229/#3196)
---------
Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
2026-06-09 22:54:21 +00:00
|
|
|
assert "notifications_permission_status" in PANELS_JS
|
2026-06-15 20:42:46 +00:00
|
|
|
assert "btn.setAttribute('aria-label', label);" in PANELS_JS
|
|
|
|
|
assert "btn.setAttribute('aria-disabled', granted?'true':'false');" in PANELS_JS
|
|
|
|
|
assert "btn.setAttribute('aria-disabled','true');" in PANELS_JS
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_granted_permission_branch_is_not_silent():
|
|
|
|
|
fn = MESSAGES_JS[
|
|
|
|
|
MESSAGES_JS.index("function requestNotificationPermission(){") :
|
|
|
|
|
MESSAGES_JS.index("function sendBrowserNotification(", MESSAGES_JS.index("function requestNotificationPermission(){"))
|
|
|
|
|
]
|
|
|
|
|
assert "if(Notification.permission==='granted'){" in fn
|
|
|
|
|
granted_branch = fn[
|
|
|
|
|
fn.index("if(Notification.permission==='granted'){") :
|
|
|
|
|
fn.index("if(Notification.permission==='denied'){")
|
|
|
|
|
]
|
|
|
|
|
assert "updateNotificationPermissionStatus()" in granted_branch
|
|
|
|
|
assert "showToast(t('notifications_enabled_toast'),3000)" in granted_branch
|
|
|
|
|
assert "return Promise.resolve('granted');" in granted_branch
|
Release v0.51.346 — Release LJ (PWA notification controls #3229) (#3897)
* Add PWA notification controls (#3229, #3196)
Rebased onto fresh master (#3229 was 281 commits behind). Routes browser
notifications through the service worker (reg.showNotification) with a direct
Notification fallback, threads the originating session deep link/tag into the
payload, and adds Enable/Send-test/permission-status controls in Settings.
notificationclick prefers an already-open target-session tab before opening a
new window. Added the 6 new i18n keys to the Polish (pl) locale block, which
the original PR missed.
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
* Apply Opus review fixes to #3229 PWA notifications
- MUST-FIX: _showPwaNotification used navigator.serviceWorker.ready, which
never settles when no SW registration ever activates (reverse-proxy MIME
mishap, SW disabled) — every notification was silently dropped, a regression
vs master. Switch to getRegistration() raced against a 2s timeout, falling
back to new Notification().
- SHOULD-FIX: notificationclick matched client.url === targetUrl exactly, but
_sessionUrlForSid copies the current query/hash into the deep link, so an
already-open session tab missed the match and spawned a duplicate window.
Compare pathnames instead.
- SHOULD-FIX: "Send test" with permission denied was a silent no-op — now
surfaces the notifications_denied toast on the force path.
- SHOULD-FIX: permission-status span went stale after granting via the button
— refresh it in requestNotificationPermission().then.
- Consistency: the request-permission grant branch now has the same
new Notification fallback as the granted branch.
- Update test_pwa_notification_controls.py to assert the pathname match.
* Stamp v0.51.346 — Release LJ (PWA notification controls #3229/#3196)
---------
Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
2026-06-09 22:54:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_notification_i18n_and_changelog_entries_exist():
|
|
|
|
|
for key in [
|
|
|
|
|
"notifications_enable_btn",
|
|
|
|
|
"notifications_test_btn",
|
|
|
|
|
"notifications_permission_status",
|
|
|
|
|
"notifications_enabled_toast",
|
|
|
|
|
"notifications_denied",
|
|
|
|
|
"notifications_unsupported",
|
|
|
|
|
]:
|
|
|
|
|
assert key in I18N_JS
|
|
|
|
|
assert "PWA notifications now use the service worker" in CHANGELOG
|
|
|
|
|
assert "#3196" in CHANGELOG
|
2026-06-15 20:42:46 +00:00
|
|
|
entry = next(
|
|
|
|
|
line for line in CHANGELOG.splitlines()
|
|
|
|
|
if "Notification permission controls now reflect the real browser state" in line
|
|
|
|
|
)
|
|
|
|
|
assert entry.count("#4118") == 1
|