Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Errors

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import sys
from urllib.parse import quote
sys.path.append(os.path.dirname(__file__))
from marionette_driver import Wait
from session_store_test_case import SessionStoreTestCase
def inline(doc):
return f"data:text/html;charset=utf-8,{quote(doc)}"
CANONICAL_URL = "https://example.com/canonical"
class TestCanonicalUrlRestore(SessionStoreTestCase):
"""
Test that canonicalUrl and hasTabNote are properly restored on pending
tabs after browser restart with session restore enabled.
Uses two tabs with restore_on_demand=True:
- tabs[0]: pending tab (not selected, stays pending)
- tabs[1]: selected tab (the last one opened)
"""
def setUp(self):
super().setUp(
startup_page=3, # Restore previous session
include_private=False,
restore_on_demand=True, # Keep non-selected tabs pending
test_windows=set([
# Two tabs - the last one opened will be selected
(
inline("<div>Tab 1</div>"),
inline("<div>Tab 2</div>"),
),
]),
)
self.marionette.set_context("chrome")
self.marionette.execute_script(
"""
Services.prefs.setBoolPref("browser.tabs.notes.enabled", true);
"""
)
def test_hasTabNote_set_after_restart(self):
self.wait_for_windows(
self.all_windows, "Not all requested windows have been opened"
)
tab_count = self.marionette.execute_script("return gBrowser.tabs.length;")
self.assertEqual(tab_count, 2, "Should have 2 tabs")
# Set canonicalUrl and note on tabs[0] (will be pending after restart)
self.marionette.execute_async_script(
f"""
let resolve = arguments[0];
(async () => {{
const {{ TabNotes }} = ChromeUtils.importESModule(
"moz-src:///browser/components/tabnotes/TabNotes.sys.mjs"
);
await TabNotes.init();
let pendingTab = gBrowser.tabs[0];
pendingTab.canonicalUrl = "{CANONICAL_URL}";
await TabNotes.set(pendingTab, "Note for pending tab");
let {{ TabStateFlusher }} = ChromeUtils.importESModule(
"resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
);
await TabStateFlusher.flushWindow(gBrowser.ownerGlobal);
}})().then(resolve);
"""
)
# Verify state before restart
result_before = self.marionette.execute_script(
"""
return {
canonicalUrl: gBrowser.tabs[0].canonicalUrl,
hasTabNote: gBrowser.tabs[0].hasTabNote
};
"""
)
self.assertEqual(
result_before["canonicalUrl"],
CANONICAL_URL,
"canonicalUrl should be set before restart",
)
self.assertTrue(
result_before["hasTabNote"],
"hasTabNote should be true before restart",
)
# Restart browser
self.marionette.quit()
self.marionette.start_session()
self.marionette.set_context("chrome")
# Wait for hasTabNote to be set on the pending tab (async due to database check)
Wait(self.marionette, timeout=10, interval=0.2).until(
lambda _: self.marionette.execute_script(
"""
return gBrowser.tabs[0].hasTabNote === true;
"""
),
message="hasTabNote should be set on pending tab after restart",
)
# Verify state after restart
result = self.marionette.execute_script(
"""
let pendingTab = gBrowser.tabs[0];
return {
isPending: pendingTab.hasAttribute("pending"),
canonicalUrl: pendingTab.canonicalUrl,
hasTabNote: pendingTab.hasTabNote
};
"""
)
self.assertTrue(result["isPending"], "Tab should be pending after restore")
self.assertEqual(
result["canonicalUrl"],
CANONICAL_URL,
"canonicalUrl should be restored on pending tab",
)
self.assertTrue(
result["hasTabNote"],
"hasTabNote should be true for pending tab with existing note",
)
def test_canonicalUrl_cleared_when_feature_disabled(self):
self.wait_for_windows(
self.all_windows, "Not all requested windows have been opened"
)
# Set canonicalUrl on a tab
self.marionette.execute_async_script(
f"""
let resolve = arguments[0];
(async () => {{
let tab = gBrowser.tabs[0];
tab.canonicalUrl = "{CANONICAL_URL}";
let {{ TabStateFlusher }} = ChromeUtils.importESModule(
"resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
);
await TabStateFlusher.flushWindow(gBrowser.ownerGlobal);
}})().then(resolve);
"""
)
canonicalUrl = self.marionette.execute_script(
"return gBrowser.tabs[0].canonicalUrl;"
)
self.assertEqual(
canonicalUrl, CANONICAL_URL, "canonicalUrl should be set before restart"
)
# Restart browser with tab notes disabled
self.marionette.execute_script(
"""
Services.prefs.setBoolPref("browser.tabs.notes.enabled", false);
"""
)
self.marionette.quit()
self.marionette.start_session()
self.marionette.set_context("chrome")
result = self.marionette.execute_script(
"""
let tab = gBrowser.tabs[0];
return {
canonicalUrl: tab.canonicalUrl,
isPending: tab.hasAttribute("pending")
};
"""
)
self.assertTrue(result["isPending"], "Tab should be pending after restore")
self.assertIsNone(
result["canonicalUrl"],
"canonicalUrl should be cleared when feature is disabled",
)
def test_hasTabNote_false_when_no_note(self):
self.skipTest("To be added in Bug 2014766 pending TabNotesController updates")