import { mock } from "jest-mock-extended"; import MainBackground from "../../background/main.background"; import { flushPromises, triggerTabOnActivatedEvent, triggerTabOnRemovedEvent, triggerTabOnReplacedEvent, triggerTabOnUpdatedEvent, triggerWindowOnFocusedChangedEvent, } from "../jest/testing-utils"; import NotificationBackground from "./notification.background"; import OverlayBackground from "./overlay.background"; import TabsBackground from "./tabs.background"; describe("TabsBackground", () => { let tabsBackgorund: TabsBackground; const mainBackground = mock({ messagingService: { send: jest.fn(), }, }); const notificationBackground = mock(); const overlayBackground = mock(); beforeEach(() => { tabsBackgorund = new TabsBackground(mainBackground, notificationBackground, overlayBackground); }); afterEach(() => { jest.clearAllMocks(); }); describe("init", () => { it("sets up a window on focusChanged listener", () => { const handleWindowOnFocusChangedSpy = jest.spyOn( tabsBackgorund as any, "handleWindowOnFocusChanged", ); tabsBackgorund.init(); expect(chrome.windows.onFocusChanged.addListener).toHaveBeenCalledWith( handleWindowOnFocusChangedSpy, ); }); }); describe("tab event listeners", () => { beforeEach(() => { tabsBackgorund.init(); }); describe("window onFocusChanged event", () => { it("ignores focus change events that do not contain a windowId", async () => { triggerWindowOnFocusedChangedEvent(undefined); await flushPromises(); expect(mainBackground.messagingService.send).not.toHaveBeenCalled(); }); it("sets the local focusedWindowId property", async () => { triggerWindowOnFocusedChangedEvent(10); await flushPromises(); expect(tabsBackgorund["focusedWindowId"]).toBe(10); }); it("updates the current tab data", async () => { triggerWindowOnFocusedChangedEvent(10); await flushPromises(); expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); }); it("sends a `windowChanged` message", async () => { triggerWindowOnFocusedChangedEvent(10); await flushPromises(); expect(mainBackground.messagingService.send).toHaveBeenCalledWith("windowChanged"); }); }); describe("handleTabOnActivated", () => { it("updates the current tab data", async () => { triggerTabOnActivatedEvent({ tabId: 10, windowId: 20 }); await flushPromises(); expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); }); it("sends a `tabChanged` message to the messaging service", async () => { triggerTabOnActivatedEvent({ tabId: 10, windowId: 20 }); await flushPromises(); expect(mainBackground.messagingService.send).toHaveBeenCalledWith("tabChanged"); }); }); describe("handleTabOnReplaced", () => { beforeEach(() => { mainBackground.onReplacedRan = false; }); it("ignores the event if the `onReplacedRan` property of the main background class is set to `true`", () => { mainBackground.onReplacedRan = true; triggerTabOnReplacedEvent(10, 20); expect(notificationBackground.checkNotificationQueue).not.toHaveBeenCalled(); }); it("checks the notification queue", () => { triggerTabOnReplacedEvent(10, 20); expect(notificationBackground.checkNotificationQueue).toHaveBeenCalled(); }); it("updates the current tab data", async () => { triggerTabOnReplacedEvent(10, 20); await flushPromises(); expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); }); it("sends a `tabChanged` message to the messaging service", async () => { triggerTabOnReplacedEvent(10, 20); await flushPromises(); expect(mainBackground.messagingService.send).toHaveBeenCalledWith("tabChanged"); }); }); describe("handleTabOnUpdated", () => { const focusedWindowId = 10; let tab: chrome.tabs.Tab; beforeEach(() => { mainBackground.onUpdatedRan = false; tabsBackgorund["focusedWindowId"] = focusedWindowId; tab = mock({ windowId: focusedWindowId, active: true, status: "loading", }); }); it("removes the cached page details from the overlay background if the tab status is `loading`", () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); expect(overlayBackground.removePageDetails).toHaveBeenCalledWith(focusedWindowId); }); it("removes the cached page details from the overlay background if the tab status is `unloaded`", () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "unloaded" }, tab); expect(overlayBackground.removePageDetails).toHaveBeenCalledWith(focusedWindowId); }); it("skips updating the current tab data the focusedWindowId is set to a value less than zero", async () => { tab.windowId = -1; triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).not.toHaveBeenCalled(); }); it("skips updating the current tab data if the updated tab is not for the focusedWindowId", async () => { tab.windowId = 20; triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).not.toHaveBeenCalled(); }); it("skips updating the current tab data if the updated tab is not active", async () => { tab.active = false; triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).not.toHaveBeenCalled(); }); it("skips updating the badge, context menu and notification bar if the `onUpdatedRan` property of the main background class is set to `true`", async () => { mainBackground.onUpdatedRan = true; triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); }); it("checks the notification queue", async () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); expect(notificationBackground.checkNotificationQueue).toHaveBeenCalled(); }); it("updates the current tab data", async () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); }); it("sends a `tabChanged` message to the messaging service", async () => { triggerTabOnUpdatedEvent(focusedWindowId, { status: "loading" }, tab); await flushPromises(); expect(mainBackground.messagingService.send).toHaveBeenCalledWith("tabChanged"); }); }); describe("handleTabOnRemoved", () => { it("removes the cached overlay page details", () => { triggerTabOnRemovedEvent(10, { windowId: 20, isWindowClosing: false }); expect(overlayBackground.removePageDetails).toHaveBeenCalledWith(10); }); }); }); });