fix(frontend): browser tab notification respects user-renamed titles; add unit test (#10406)

This commit is contained in:
Engel Nyst 2025-08-16 09:00:45 +02:00 committed by GitHub
parent 794381c22b
commit 0ec6ed20cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 61 additions and 7 deletions

View File

@ -0,0 +1,51 @@
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { browserTab } from "#/utils/browser-tab";
// These tests exercise the browser-tab notification flasher behavior.
// Specifically we verify that when the document title changes externally
// while a notification is active, the flasher updates its internal
// baseline so it restores/toggles to the new title instead of an old one.
describe("browserTab notifications", () => {
const MESSAGE = "Agent ready";
const INITIAL = "Conversation 123 | OpenHands";
const RENAMED = "My renamed title | OpenHands";
beforeEach(() => {
vi.useFakeTimers();
// reset title for each test
document.title = INITIAL;
});
afterEach(() => {
browserTab.stopNotification();
vi.runOnlyPendingTimers();
vi.useRealTimers();
});
it("updates baseline when title changes during an active notification and restores to the new title", () => {
// Start flashing
browserTab.startNotification(MESSAGE);
// Tick once: should switch to the message
vi.advanceTimersByTime(1000);
expect(document.title).toBe(MESSAGE);
// Simulate an external rename while flashing (e.g., user edits title)
document.title = RENAMED;
// Next tick: flasher observes the external change and updates baseline
vi.advanceTimersByTime(1000);
// On this tick, we toggle back to the message
expect(document.title).toBe(MESSAGE);
// Next tick should toggle to the updated baseline (renamed title)
vi.advanceTimersByTime(1000);
expect(document.title).toBe(RENAMED);
// Stop flashing: title should remain the updated baseline
browserTab.stopNotification();
expect(document.title).toBe(RENAMED);
});
});

View File

@ -11,20 +11,23 @@ export const browserTab = {
startNotification(message: string) {
if (!isBrowser) return;
// Store original title if not already stored
if (!originalTitle) {
originalTitle = document.title;
}
// Always capture the current title as the baseline to restore to
originalTitle = document.title;
// Clear any existing interval
if (titleInterval) {
this.stopNotification();
}
// Alternate between original title and notification message
// Alternate between the latest baseline title and the notification message.
// If the title changes externally (e.g., user renames conversation),
// update the baseline so we restore to the new value when stopping.
titleInterval = window.setInterval(() => {
document.title =
document.title === originalTitle ? message : originalTitle;
const current = document.title;
if (current !== originalTitle && current !== message) {
originalTitle = current;
}
document.title = current === message ? originalTitle : message;
}, 1000);
// Set favicon to indicate notification