Settings: the test notification shows in the tab you're in #62
No files matched your search
@@ -0,0 +1,46 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { showNotification } from "@/lib/notify/notify";
|
||||
|
||||
/**
|
||||
* The Settings test button runs in a visible, focused tab, which is exactly
|
||||
* when a new-mail notification is held back. It has to show anyway (#48).
|
||||
*/
|
||||
describe("showNotification", () => {
|
||||
const shown = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
shown.mockClear();
|
||||
class FakeNotification {
|
||||
static permission = "granted";
|
||||
onclick: (() => void) | null = null;
|
||||
constructor(title: string) {
|
||||
shown(title);
|
||||
}
|
||||
close() {}
|
||||
}
|
||||
vi.stubGlobal("Notification", FakeNotification);
|
||||
vi.spyOn(document, "visibilityState", "get").mockReturnValue("visible");
|
||||
vi.spyOn(document, "hasFocus").mockReturnValue(true);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("holds back new mail in a tab you are looking at", () => {
|
||||
showNotification("New mail");
|
||||
expect(shown).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows a forced one in that same tab", () => {
|
||||
showNotification("ihasmail test", { force: true });
|
||||
expect(shown).toHaveBeenCalledWith("ihasmail test");
|
||||
});
|
||||
|
||||
it("still shows nothing without permission, forced or not", () => {
|
||||
(Notification as unknown as { permission: string }).permission = "denied";
|
||||
showNotification("ihasmail test", { force: true });
|
||||
expect(shown).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -91,10 +91,13 @@ export async function requestNotificationPermission(): Promise<NotificationPermi
|
||||
* for the same message (`ihasmail-<id>`), so if both ever show it, the second
|
||||
* replaces the first instead of stacking beside it.
|
||||
*/
|
||||
export function showNotification(title: string, opts: NotificationOptions & { onClick?: () => void } = {}): void {
|
||||
export function showNotification(title: string, opts: NotificationOptions & { onClick?: () => void; force?: boolean } = {}): void {
|
||||
if (!("Notification" in window) || Notification.permission !== "granted") return;
|
||||
if (document.visibilityState === "visible" && document.hasFocus()) return;
|
||||
const { onClick, ...options } = opts;
|
||||
// New mail in a tab you're looking at needs no notification. A test asked
|
||||
// for from Settings is always in such a tab, so it says to show anyway
|
||||
// (coffey-labs/ihasmail#48).
|
||||
if (!opts.force && document.visibilityState === "visible" && document.hasFocus()) return;
|
||||
const { onClick, force: _force, ...options } = opts;
|
||||
const full = { icon: brandImage("/img/icon-192.png"), badge: brandImage("/img/favicon-64.png"), ...options };
|
||||
const viaWorker = navigator.serviceWorker?.controller ? navigator.serviceWorker.ready : null;
|
||||
if (viaWorker) {
|
||||
|
||||
@@ -81,7 +81,7 @@ export function NotificationsSettings() {
|
||||
/>
|
||||
<Switch locked={isEnforced("notificationSound")} checked={s.notificationSound} onChange={(v) => update({ notificationSound: v })} label={t("Play a sound for new mail")} />
|
||||
<div className="row mt-16">
|
||||
<button className="btn" onClick={() => { showNotification(t("{app} test", { app: appName }), { body: t("This is what a new-mail notification looks like.") }); playNewMailSound(); }}>{t("Test notification")}</button>
|
||||
<button className="btn" onClick={() => { showNotification(t("{app} test", { app: appName }), { body: t("This is what a new-mail notification looks like."), force: true }); playNewMailSound(); }}>{t("Test notification")}</button>
|
||||
</div>
|
||||
<p className="hint mt-8">{t("The tab title and favicon always show your unread Inbox count.")}</p>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user