From 0bb57bf4604b5fa8d589b8b1de619e483e19f4fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 11:54:12 +0000 Subject: [PATCH 1/6] Initial plan From a7b7113c59ccdbf3c8938b4db95b587a9ad155af Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 12:03:22 +0000 Subject: [PATCH 2/6] Track pending navigation URLs Agent-Logs-Url: https://github.com/salarcode/SmartProxy/sessions/ce813f92-b526-45e7-b41c-0b2152e4e5a2 Co-authored-by: salarcode <1272095+salarcode@users.noreply.github.com> --- package.json | 12 +++++ src/core/TabManager.ts | 65 ++++++++++++++++++++++++ src/manifest-chrome-mv2.json | 1 + src/manifest-chrome.json | 1 + src/manifest-edge.json | 1 + src/manifest-firefox-android.json | 1 + src/manifest-firefox-unlisted.json | 7 +-- src/manifest-firefox.json | 7 +-- src/manifest-opera.json | 1 + src/manifest-thunderbird.json | 1 + src/tests/TabManager.test.ts | 81 ++++++++++++++++++++++++++++++ 11 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 src/tests/TabManager.test.ts diff --git a/package.json b/package.json index 4edf9adb..695b6a7d 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,18 @@ "build-th": "webpack --env browser=thunderbird", "build-th:watch": "webpack --watch --env browser=thunderbird --env dev=true" }, + "jest": { + "setupFiles": [ + "jest-webextension-mock" + ], + "testEnvironment": "jsdom", + "testMatch": [ + "**/src/tests/**/*.test.ts" + ], + "transform": { + "^.+\\.tsx?$": "ts-jest" + } + }, "license": "GPL-3.0", "dependencies": { "pako": "^2.1.0", diff --git a/src/core/TabManager.ts b/src/core/TabManager.ts index 2549650c..86a60fff 100644 --- a/src/core/TabManager.ts +++ b/src/core/TabManager.ts @@ -44,6 +44,20 @@ export class TabManager { // listen to tab URL changes api.tabs.onUpdated.addListener(TabManager.updateActiveTab); + let webNavigation = api["webNavigation"]; + if (webNavigation) { + if (webNavigation.onBeforeNavigate) + webNavigation.onBeforeNavigate.addListener(TabManager.handleNavigationStarted); + if (webNavigation.onCommitted) + webNavigation.onCommitted.addListener(TabManager.handleNavigationCommitted); + if (webNavigation.onHistoryStateUpdated) + webNavigation.onHistoryStateUpdated.addListener(TabManager.handleNavigationCommitted); + if (webNavigation.onReferenceFragmentUpdated) + webNavigation.onReferenceFragmentUpdated.addListener(TabManager.handleNavigationCommitted); + if (webNavigation.onErrorOccurred) + webNavigation.onErrorOccurred.addListener(TabManager.handleNavigationError); + } + api.tabs.onRemoved.addListener(TabManager.handleTabRemoved); // listen for window switching @@ -192,6 +206,57 @@ export class TabManager { tabData.clearFailedRequests(); } + private static isMainFrameNavigation(details: any): boolean { + return details && details.tabId > -1 && details.frameId === 0 && details.url; + } + + private static handleNavigationStarted(details: any) { + if (!TabManager.isMainFrameNavigation(details)) + return; + + TabManager.updateTabUrlFromNavigation(details.tabId, details.url); + } + + private static handleNavigationCommitted(details: any) { + if (!TabManager.isMainFrameNavigation(details)) + return; + + TabManager.updateTabUrlFromNavigation(details.tabId, details.url); + } + + private static handleNavigationError(details: any) { + if (!TabManager.isMainFrameNavigation(details)) + return; + + let tabData = TabManager.tabs[details.tabId]; + if (!tabData || tabData.url != details.url) + return; + + TabManager.loadTabData(tabData); + } + + private static updateTabUrlFromNavigation(tabId: number, url: string) { + let tabData = TabManager.tabs[tabId]; + let tabDataCreated = false; + if (!tabData) { + tabData = TabManager.getOrSetTab(tabId, false, url); + tabDataCreated = true; + } + + if (!tabDataCreated && tabData.url == url) + return; + + tabData.clearFailedRequests(); + tabData.resetTabState(); + TabManager.setRuleForProxyPerOrigin(tabData, url); + tabData.updated = new Date(); + tabData.url = url; + if (!tabData.proxifiedParentDocumentUrl) + tabData.proxifiedParentDocumentUrl = url; + + TabManager.onTabUpdated.trigger(tabData); + } + private static handleTabUpdated(tabId: number, changeInfo: any, tabInfo: any) { // only if url of the page is changed diff --git a/src/manifest-chrome-mv2.json b/src/manifest-chrome-mv2.json index 6c9e67c3..77021c0d 100644 --- a/src/manifest-chrome-mv2.json +++ b/src/manifest-chrome-mv2.json @@ -17,6 +17,7 @@ "", "activeTab", "tabs", + "webNavigation", "proxy", "webRequest", "webRequestBlocking", diff --git a/src/manifest-chrome.json b/src/manifest-chrome.json index 24e615d9..6ed61960 100644 --- a/src/manifest-chrome.json +++ b/src/manifest-chrome.json @@ -16,6 +16,7 @@ "permissions": [ "activeTab", "tabs", + "webNavigation", "proxy", "webRequest", "webRequestAuthProvider", diff --git a/src/manifest-edge.json b/src/manifest-edge.json index 2aa4ad42..f7576b4c 100644 --- a/src/manifest-edge.json +++ b/src/manifest-edge.json @@ -17,6 +17,7 @@ "", "activeTab", "tabs", + "webNavigation", "proxy", "webRequest", "webRequestBlocking", diff --git a/src/manifest-firefox-android.json b/src/manifest-firefox-android.json index 969f94b1..27f30f4a 100644 --- a/src/manifest-firefox-android.json +++ b/src/manifest-firefox-android.json @@ -17,6 +17,7 @@ "", "activeTab", "tabs", + "webNavigation", "proxy", "webRequest", "webRequestBlocking", diff --git a/src/manifest-firefox-unlisted.json b/src/manifest-firefox-unlisted.json index 642de991..fe3ad308 100644 --- a/src/manifest-firefox-unlisted.json +++ b/src/manifest-firefox-unlisted.json @@ -15,9 +15,10 @@ }, "permissions": [ "", - "activeTab", - "tabs", - "proxy", + "activeTab", + "tabs", + "webNavigation", + "proxy", "webRequest", "webRequestBlocking", "storage", diff --git a/src/manifest-firefox.json b/src/manifest-firefox.json index 8751c782..c51d8c2b 100644 --- a/src/manifest-firefox.json +++ b/src/manifest-firefox.json @@ -15,9 +15,10 @@ }, "permissions": [ "", - "activeTab", - "tabs", - "proxy", + "activeTab", + "tabs", + "webNavigation", + "proxy", "webRequest", "webRequestBlocking", "storage", diff --git a/src/manifest-opera.json b/src/manifest-opera.json index 468b1254..2f182688 100644 --- a/src/manifest-opera.json +++ b/src/manifest-opera.json @@ -17,6 +17,7 @@ "", "activeTab", "tabs", + "webNavigation", "proxy", "webRequest", "webRequestBlocking", diff --git a/src/manifest-thunderbird.json b/src/manifest-thunderbird.json index 537ab4f8..fc2adfee 100644 --- a/src/manifest-thunderbird.json +++ b/src/manifest-thunderbird.json @@ -17,6 +17,7 @@ "", "activeTab", "tabs", + "webNavigation", "proxy", "webRequest", "webRequestBlocking", diff --git a/src/tests/TabManager.test.ts b/src/tests/TabManager.test.ts new file mode 100644 index 00000000..2bbfabce --- /dev/null +++ b/src/tests/TabManager.test.ts @@ -0,0 +1,81 @@ +jest.mock('../lib/environment', () => ({ + environment: { + chrome: true, + name: 'chrome', + version: 1, + manifestV3: false, + notSupported: {}, + notAllowed: {}, + bugFreeVersions: {}, + initialConfig: {}, + storageQuota: { syncQuotaBytesPerItem: () => 8000 }, + browserConfig: {} + }, + api: { + runtime: { lastError: null }, + browserAction: {}, + i18n: { getMessage: (key: string) => key }, + tabs: {} + } +})); + +import { api } from '../lib/environment'; +import { TabManager } from '../core/TabManager'; + +const tabManagerType = TabManager as any; + +describe('TabManager webNavigation tracking', () => { + beforeEach(() => { + tabManagerType.tabs = {}; + tabManagerType.currentTab = null; + api.runtime.lastError = null; + api.tabs.get = jest.fn((tabId: number, callback: Function) => callback({ + id: tabId, + url: 'https://current.example/', + incognito: false, + index: 0 + })); + }); + + it('updates the tab url when main-frame navigation starts', () => { + let tabData = TabManager.getOrSetTab(1, false, 'https://old.example/'); + let updates = 0; + const onUpdated = () => updates++; + TabManager.TabUpdated.on(onUpdated); + + tabManagerType.handleNavigationStarted({ + tabId: 1, + frameId: 0, + url: 'https://new.example/path' + }); + + TabManager.TabUpdated.off(onUpdated); + expect(tabData.url).toBe('https://new.example/path'); + expect(tabData.proxifiedParentDocumentUrl).toBe('https://new.example/path'); + expect(updates).toBe(1); + }); + + it('ignores sub-frame navigation changes', () => { + let tabData = TabManager.getOrSetTab(1, false, 'https://old.example/'); + + tabManagerType.handleNavigationStarted({ + tabId: 1, + frameId: 1, + url: 'https://subframe.example/' + }); + + expect(tabData.url).toBe('https://old.example/'); + }); + + it('reloads current document url when pending navigation fails', () => { + let tabData = TabManager.getOrSetTab(1, false, 'https://loading.example/'); + + tabManagerType.handleNavigationError({ + tabId: 1, + frameId: 0, + url: 'https://loading.example/' + }); + + expect(tabData.url).toBe('https://current.example/'); + }); +}); From cdbea0bc393e489beb543ea164bc10640474b302 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 12:05:02 +0000 Subject: [PATCH 3/6] Address navigation tracking review feedback Agent-Logs-Url: https://github.com/salarcode/SmartProxy/sessions/ce813f92-b526-45e7-b41c-0b2152e4e5a2 Co-authored-by: salarcode <1272095+salarcode@users.noreply.github.com> --- src/core/TabManager.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/TabManager.ts b/src/core/TabManager.ts index 86a60fff..53d1ca5e 100644 --- a/src/core/TabManager.ts +++ b/src/core/TabManager.ts @@ -229,7 +229,7 @@ export class TabManager { return; let tabData = TabManager.tabs[details.tabId]; - if (!tabData || tabData.url != details.url) + if (!tabData || tabData.url !== details.url) return; TabManager.loadTabData(tabData); @@ -243,7 +243,7 @@ export class TabManager { tabDataCreated = true; } - if (!tabDataCreated && tabData.url == url) + if (!tabDataCreated && tabData.url === url) return; tabData.clearFailedRequests(); @@ -365,4 +365,4 @@ export class TabDataStatuses { /** Always enabled has bypassed and no proxy is applied */ public hasAlwaysEnabledByPassed: boolean; -} \ No newline at end of file +} From d5bd23a7d4d7347fc1b42fb2d7c1f0615f55c343 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 19 May 2026 12:06:41 +0000 Subject: [PATCH 4/6] Update navigation URL state consistently Agent-Logs-Url: https://github.com/salarcode/SmartProxy/sessions/ce813f92-b526-45e7-b41c-0b2152e4e5a2 Co-authored-by: salarcode <1272095+salarcode@users.noreply.github.com> --- src/core/TabManager.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/TabManager.ts b/src/core/TabManager.ts index 53d1ca5e..c4c6bc58 100644 --- a/src/core/TabManager.ts +++ b/src/core/TabManager.ts @@ -44,7 +44,7 @@ export class TabManager { // listen to tab URL changes api.tabs.onUpdated.addListener(TabManager.updateActiveTab); - let webNavigation = api["webNavigation"]; + let webNavigation = api.webNavigation; if (webNavigation) { if (webNavigation.onBeforeNavigate) webNavigation.onBeforeNavigate.addListener(TabManager.handleNavigationStarted); @@ -251,8 +251,7 @@ export class TabManager { TabManager.setRuleForProxyPerOrigin(tabData, url); tabData.updated = new Date(); tabData.url = url; - if (!tabData.proxifiedParentDocumentUrl) - tabData.proxifiedParentDocumentUrl = url; + tabData.proxifiedParentDocumentUrl = url; TabManager.onTabUpdated.trigger(tabData); } From 23577fc96ea42210e116c0ba6f19f082f6f4a6cc Mon Sep 17 00:00:00 2001 From: salarcode Date: Mon, 17 Aug 2026 01:08:49 +1000 Subject: [PATCH 5/6] Fixing bugs --- src/core/TabManager.ts | 28 ++++++++++++++++++------- src/lib/Utils.ts | 40 ++++++++++++++++++++++++++++++++++++ src/tests/TabManager.test.ts | 30 +++++++++++++++++++++++++++ src/tests/Utils.test.ts | 32 +++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+), 7 deletions(-) diff --git a/src/core/TabManager.ts b/src/core/TabManager.ts index c4c6bc58..f4414425 100644 --- a/src/core/TabManager.ts +++ b/src/core/TabManager.ts @@ -20,6 +20,7 @@ import { CompiledProxyRule, FailedRequestType, ProxyServer, TabProxyStatus } fro import { api, environment } from "../lib/environment"; import { Settings } from "./Settings"; import { ProxyRules } from "./ProxyRules"; +import { Utils } from "../lib/Utils"; export class TabManager { @@ -100,19 +101,28 @@ export class TabManager { if (!tabData) { tabData = TabManager.getOrSetTab(tabId, false); } - if (tabData.proxifiedParentDocumentUrl != tabInfo.url) { + + // Chrome may expose the destination as pendingUrl while url is still the old/placeholder page. + // Firefox only has url, and during loading that is often about:blank / about:newtab. + let incomingUrl = tabInfo.pendingUrl || tabInfo.url || ""; + let keepExistingUrl = Utils.shouldPreserveTrackedUrl(tabData.url, incomingUrl, tabInfo.status, tabInfo.pendingUrl); + let effectiveUrl = keepExistingUrl ? tabData.url : incomingUrl; + + if (effectiveUrl && tabData.proxifiedParentDocumentUrl != effectiveUrl) { // resettings the state tabData.resetTabState(); // apply `proxified` value - TabManager.setRuleForProxyPerOrigin(tabData, tabInfo.url); + TabManager.setRuleForProxyPerOrigin(tabData, effectiveUrl); } tabData.updated = new Date(); tabData.incognito = tabInfo.incognito; - tabData.url = tabInfo.url; tabData.index = tabInfo.index; - if (!tabData.proxifiedParentDocumentUrl) - tabData.proxifiedParentDocumentUrl = tabInfo.url; + if (effectiveUrl) { + tabData.url = effectiveUrl; + if (!tabData.proxifiedParentDocumentUrl) + tabData.proxifiedParentDocumentUrl = effectiveUrl; + } // saving the tab in the storage TabManager.tabs[tabId] = tabData; @@ -216,7 +226,6 @@ export class TabManager { TabManager.updateTabUrlFromNavigation(details.tabId, details.url); } - private static handleNavigationCommitted(details: any) { if (!TabManager.isMainFrameNavigation(details)) return; @@ -253,6 +262,8 @@ export class TabManager { tabData.url = url; tabData.proxifiedParentDocumentUrl = url; + if (!TabManager.currentTab || TabManager.currentTab.tabId === tabId) + TabManager.currentTab = tabData; TabManager.onTabUpdated.trigger(tabData); } @@ -292,7 +303,10 @@ export class TabManager { if (tabData) { // reload tab data tabData.clearFailedRequests(); - TabManager.loadTabData(tabData); + if (changeInfo.url && + !Utils.shouldPreserveTrackedUrl(tabData.url, changeInfo.url, changeInfo.status || tabInfo?.status, tabInfo?.pendingUrl)) { + TabManager.updateTabUrlFromNavigation(tabId, changeInfo.url); + } callOnUpdate = true; } } diff --git a/src/lib/Utils.ts b/src/lib/Utils.ts index 65d85f4b..ba218d3f 100644 --- a/src/lib/Utils.ts +++ b/src/lib/Utils.ts @@ -272,6 +272,46 @@ export class Utils { catch (e) { return false; } } + /** New-tab placeholders reported by tabs.query/get while a real navigation is already in flight. */ + public static isTransientTabUrl(url: string): boolean { + if (!url) + return true; + + let value = url.toLowerCase(); + return value === "about:blank" + || value === "about:newtab" + || value === "about:home" + || value === "about:privatebrowsing" + || value.startsWith("chrome://newtab") + || value.startsWith("chrome://new-tab-page") + || value.startsWith("edge://newtab"); + } + + /** + * tabs.Tab.url lags webNavigation in both Firefox and Chrome. + * Keep the tracked URL when the tabs API is still on a placeholder or the previous page. + */ + public static shouldPreserveTrackedUrl(existingUrl: string, incomingUrl: string, tabStatus?: string, pendingUrl?: string): boolean { + if (!existingUrl) + return false; + if (!incomingUrl) + return true; + if (incomingUrl === existingUrl) + return false; + if (Utils.isTransientTabUrl(incomingUrl) && !Utils.isTransientTabUrl(existingUrl)) + return true; + + // During loading, Firefox keeps about:blank and Chrome often still reports the previous committed URL. + // Only accept a different URL in that state when Chrome exposes it as pendingUrl. + if (tabStatus === "loading") { + if (pendingUrl && incomingUrl === pendingUrl && !Utils.isTransientTabUrl(incomingUrl)) + return false; + return true; + } + + return false; + } + public static urlHasSchema(url: string): boolean { // note: this will accept like http:/example.org/ in Chrome and Firefox if (!url) diff --git a/src/tests/TabManager.test.ts b/src/tests/TabManager.test.ts index 2bbfabce..cfa3e9a6 100644 --- a/src/tests/TabManager.test.ts +++ b/src/tests/TabManager.test.ts @@ -78,4 +78,34 @@ describe('TabManager webNavigation tracking', () => { expect(tabData.url).toBe('https://current.example/'); }); + + it('does not let a loading placeholder from tabs.query overwrite webNavigation url', () => { + let tabData = TabManager.getOrSetTab(56, false, 'https://example.com/'); + + TabManager.updateTabData(tabData, { + id: 56, + url: 'about:blank', + status: 'loading', + incognito: false, + index: 4 + }); + + expect(tabData.url).toBe('https://example.com/'); + expect(tabData.index).toBe(4); + }); + + it('accepts chrome pendingUrl during loading', () => { + let tabData = TabManager.getOrSetTab(56, false, 'https://old.example/'); + + TabManager.updateTabData(tabData, { + id: 56, + url: 'https://old.example/', + pendingUrl: 'https://new.example/', + status: 'loading', + incognito: false, + index: 1 + }); + + expect(tabData.url).toBe('https://new.example/'); + }); }); diff --git a/src/tests/Utils.test.ts b/src/tests/Utils.test.ts index 2dfbee40..740b57fc 100644 --- a/src/tests/Utils.test.ts +++ b/src/tests/Utils.test.ts @@ -16,6 +16,38 @@ describe('Utils', () => { }); }); + describe('isTransientTabUrl', () => { + it('treats new-tab placeholders as transient', () => { + expect(Utils.isTransientTabUrl('')).toBe(true); + expect(Utils.isTransientTabUrl('about:blank')).toBe(true); + expect(Utils.isTransientTabUrl('about:newtab')).toBe(true); + expect(Utils.isTransientTabUrl('chrome://newtab/')).toBe(true); + }); + + it('does not treat real pages as transient', () => { + expect(Utils.isTransientTabUrl('https://example.com/')).toBe(false); + }); + }); + + describe('shouldPreserveTrackedUrl', () => { + it('keeps a real URL when tabs.query reports a loading placeholder', () => { + expect(Utils.shouldPreserveTrackedUrl('https://example.com/', 'about:blank', 'loading')).toBe(true); + }); + + it('keeps a real URL when tabs.query has no url yet', () => { + expect(Utils.shouldPreserveTrackedUrl('https://example.com/', '', 'loading')).toBe(true); + }); + + it('accepts chrome pendingUrl during loading', () => { + expect(Utils.shouldPreserveTrackedUrl( + 'https://old.example/', + 'https://new.example/', + 'loading', + 'https://new.example/' + )).toBe(false); + }); + }); + describe('extractHostFromUrl', () => { it('should extract hostname from URL', () => { expect(Utils.extractHostFromUrl('https://example.com/path')).toBe('example.com'); From f537fb2fce1a52c0148e94d0d0a67340b5a19573 Mon Sep 17 00:00:00 2001 From: salarcode Date: Mon, 17 Aug 2026 01:23:24 +1000 Subject: [PATCH 6/6] feedbacks --- src/core/TabManager.ts | 5 +++-- src/lib/Utils.ts | 17 ++++------------- src/tests/TabManager.test.ts | 17 ++++++++++++++++- src/tests/Utils.test.ts | 13 ++++--------- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/core/TabManager.ts b/src/core/TabManager.ts index f4414425..ba9bd107 100644 --- a/src/core/TabManager.ts +++ b/src/core/TabManager.ts @@ -105,7 +105,7 @@ export class TabManager { // Chrome may expose the destination as pendingUrl while url is still the old/placeholder page. // Firefox only has url, and during loading that is often about:blank / about:newtab. let incomingUrl = tabInfo.pendingUrl || tabInfo.url || ""; - let keepExistingUrl = Utils.shouldPreserveTrackedUrl(tabData.url, incomingUrl, tabInfo.status, tabInfo.pendingUrl); + let keepExistingUrl = Utils.shouldPreserveTrackedUrl(tabData.url, incomingUrl); let effectiveUrl = keepExistingUrl ? tabData.url : incomingUrl; if (effectiveUrl && tabData.proxifiedParentDocumentUrl != effectiveUrl) { @@ -226,6 +226,7 @@ export class TabManager { TabManager.updateTabUrlFromNavigation(details.tabId, details.url); } + private static handleNavigationCommitted(details: any) { if (!TabManager.isMainFrameNavigation(details)) return; @@ -304,7 +305,7 @@ export class TabManager { // reload tab data tabData.clearFailedRequests(); if (changeInfo.url && - !Utils.shouldPreserveTrackedUrl(tabData.url, changeInfo.url, changeInfo.status || tabInfo?.status, tabInfo?.pendingUrl)) { + !Utils.shouldPreserveTrackedUrl(tabData.url, changeInfo.url)) { TabManager.updateTabUrlFromNavigation(tabId, changeInfo.url); } callOnUpdate = true; diff --git a/src/lib/Utils.ts b/src/lib/Utils.ts index ba218d3f..0af589cc 100644 --- a/src/lib/Utils.ts +++ b/src/lib/Utils.ts @@ -289,27 +289,18 @@ export class Utils { /** * tabs.Tab.url lags webNavigation in both Firefox and Chrome. - * Keep the tracked URL when the tabs API is still on a placeholder or the previous page. + * Preserve the tracked URL only when the tabs API has no URL or is still + * reporting a new-tab placeholder. */ - public static shouldPreserveTrackedUrl(existingUrl: string, incomingUrl: string, tabStatus?: string, pendingUrl?: string): boolean { + public static shouldPreserveTrackedUrl(existingUrl: string, incomingUrl: string): boolean { if (!existingUrl) return false; if (!incomingUrl) return true; if (incomingUrl === existingUrl) return false; - if (Utils.isTransientTabUrl(incomingUrl) && !Utils.isTransientTabUrl(existingUrl)) - return true; - - // During loading, Firefox keeps about:blank and Chrome often still reports the previous committed URL. - // Only accept a different URL in that state when Chrome exposes it as pendingUrl. - if (tabStatus === "loading") { - if (pendingUrl && incomingUrl === pendingUrl && !Utils.isTransientTabUrl(incomingUrl)) - return false; - return true; - } - return false; + return Utils.isTransientTabUrl(incomingUrl) && !Utils.isTransientTabUrl(existingUrl); } public static urlHasSchema(url: string): boolean { diff --git a/src/tests/TabManager.test.ts b/src/tests/TabManager.test.ts index cfa3e9a6..d11f9639 100644 --- a/src/tests/TabManager.test.ts +++ b/src/tests/TabManager.test.ts @@ -94,7 +94,7 @@ describe('TabManager webNavigation tracking', () => { expect(tabData.index).toBe(4); }); - it('accepts chrome pendingUrl during loading', () => { + it('accepts chrome pendingUrl from the tabs API', () => { let tabData = TabManager.getOrSetTab(56, false, 'https://old.example/'); TabManager.updateTabData(tabData, { @@ -108,4 +108,19 @@ describe('TabManager webNavigation tracking', () => { expect(tabData.url).toBe('https://new.example/'); }); + + it('accepts tabs.onUpdated url when webNavigation is unavailable', () => { + let tabData = TabManager.getOrSetTab(1, false, 'https://old.example/'); + + tabManagerType.handleTabUpdated(1, { + url: 'https://new.example/', + status: 'loading' + }, { + id: 1, + url: 'https://new.example/', + status: 'loading' + }); + + expect(tabData.url).toBe('https://new.example/'); + }); }); diff --git a/src/tests/Utils.test.ts b/src/tests/Utils.test.ts index 740b57fc..e2279aca 100644 --- a/src/tests/Utils.test.ts +++ b/src/tests/Utils.test.ts @@ -31,20 +31,15 @@ describe('Utils', () => { describe('shouldPreserveTrackedUrl', () => { it('keeps a real URL when tabs.query reports a loading placeholder', () => { - expect(Utils.shouldPreserveTrackedUrl('https://example.com/', 'about:blank', 'loading')).toBe(true); + expect(Utils.shouldPreserveTrackedUrl('https://example.com/', 'about:blank')).toBe(true); }); it('keeps a real URL when tabs.query has no url yet', () => { - expect(Utils.shouldPreserveTrackedUrl('https://example.com/', '', 'loading')).toBe(true); + expect(Utils.shouldPreserveTrackedUrl('https://example.com/', '')).toBe(true); }); - it('accepts chrome pendingUrl during loading', () => { - expect(Utils.shouldPreserveTrackedUrl( - 'https://old.example/', - 'https://new.example/', - 'loading', - 'https://new.example/' - )).toBe(false); + it('accepts a real tabs url even while the tab is loading', () => { + expect(Utils.shouldPreserveTrackedUrl('https://old.example/', 'https://current.example/')).toBe(false); }); });