tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit dc10e26ff5f635ef1a116b60f8dbd2e628891646
parent 5945d82e289bbad6935b42f5867abcd9d1cc4975
Author: Tom Schuster <tschuster@mozilla.com>
Date:   Thu, 20 Nov 2025 11:16:16 +0000

Bug 2000196 - Compare favicons using new ImageTestUtils. r=tnikkel

Differential Revision: https://phabricator.services.mozilla.com/D273007

Diffstat:
Mbrowser/base/content/test/favicons/browser_favicon_empty_data.js | 11++++++++++-
Mbrowser/components/originattributes/test/browser/browser_favicon_firstParty.js | 23++++++++++++++++-------
Mbrowser/components/sessionstore/test/browser_tabicon_after_bg_tab_crash.js | 15+++++++++++++--
Mdevtools/client/aboutdebugging/test/browser/browser_aboutdebugging_tab_favicons.js | 13++++++++-----
Atesting/modules/ImageTestUtils.sys.mjs | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtesting/modules/moz.build | 1+
6 files changed, 113 insertions(+), 15 deletions(-)

diff --git a/browser/base/content/test/favicons/browser_favicon_empty_data.js b/browser/base/content/test/favicons/browser_favicon_empty_data.js @@ -3,6 +3,10 @@ "use strict"; +const { ImageTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/ImageTestUtils.sys.mjs" +); + const TEST_ROOT = "http://mochi.test:8888/browser/browser/base/content/test/favicons/"; @@ -22,7 +26,12 @@ add_task(async function () { .getTabForBrowser(browser) .querySelector(".tab-icon-image"); await addContentLinkForIconUrl(ICON_URL, browser); - Assert.equal(browser.mIconURL, ICON_DATAURI, "Favicon is correctly set."); + await ImageTestUtils.assertEqualImage( + window, + browser.mIconURL, + ICON_DATAURI, + "Favicon is correctly set." + ); // Give some time to ensure the icon is rendered. /* eslint-disable mozilla/no-arbitrary-setTimeout */ diff --git a/browser/components/originattributes/test/browser/browser_favicon_firstParty.js b/browser/components/originattributes/test/browser/browser_favicon_firstParty.js @@ -12,6 +12,10 @@ const { PlacesTestUtils } = ChromeUtils.importESModule( "resource://testing-common/PlacesTestUtils.sys.mjs" ); +const { ImageTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/ImageTestUtils.sys.mjs" +); + const FIRST_PARTY_ONE = "example.com"; const FIRST_PARTY_TWO = "example.org"; const THIRD_PARTY = "example.net"; @@ -222,14 +226,19 @@ async function generateCookies(aThirdParty) { return cookies; } -function assertIconIsData(item) { +async function assertIconIsData(item) { let icon = item.getAttribute("image"); is( icon.substring(0, 5), "data:", "Expected the image element to be a data URI" ); - is(icon, ICON_DATA, "Expected to see the correct data."); + await ImageTestUtils.assertEqualImage( + window, + icon, + ICON_DATA, + "Expected to see the correct data." + ); } async function doTest(aTestPage, aExpectedCookies, aFaviconURL) { @@ -255,7 +264,7 @@ async function doTest(aTestPage, aExpectedCookies, aFaviconURL) { // Waiting until favicon loaded. await promiseFaviconLoaded; - assertIconIsData(tabInfo.tab); + await assertIconIsData(tabInfo.tab); BrowserTestUtils.removeTab(tabInfo.tab); // FIXME: We need to wait for the next event tick here to avoid observing @@ -300,7 +309,7 @@ async function doTestForAllTabsFavicon( // Waiting until the favicon loaded. await promiseFaviconLoaded; - assertIconIsData(tabInfo.tab); + await assertIconIsData(tabInfo.tab); gTabsPanel.init(); @@ -313,7 +322,7 @@ async function doTestForAllTabsFavicon( gTabsPanel.showAllTabsPanel(); await allTabsPopupShownPromise; - assertIconIsData( + await assertIconIsData( gTabsPanel.allTabsViewTabs.lastElementChild.firstElementChild ); @@ -341,7 +350,7 @@ async function doTestForAllTabsFavicon( // Wait until the favicon is fully loaded. await promiseFaviconLoaded; - assertIconIsData(tabInfo.tab); + await assertIconIsData(tabInfo.tab); // Make the popup of allTabs showing up again. allTabsPopupShownPromise = BrowserTestUtils.waitForEvent( @@ -351,7 +360,7 @@ async function doTestForAllTabsFavicon( gTabsPanel.showAllTabsPanel(); await allTabsPopupShownPromise; - assertIconIsData( + await assertIconIsData( gTabsPanel.allTabsViewTabs.lastElementChild.firstElementChild ); diff --git a/browser/components/sessionstore/test/browser_tabicon_after_bg_tab_crash.js b/browser/components/sessionstore/test/browser_tabicon_after_bg_tab_crash.js @@ -1,5 +1,9 @@ "use strict"; +const { ImageTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/ImageTestUtils.sys.mjs" +); + const FAVICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAARElEQVQYV2NkYLj3nwEnUGKEMxkYGBghilEFIQBTHKqYOIDFZHQ+DNz7j0MxdoDDGThNRgfoNsEATsXYARbFuAHtFAMAuvMbOrNomdAAAAAASUVORK5CYII="; const PAGE_URL = `data:text/html, @@ -36,13 +40,20 @@ add_task(async function test_tabicon_after_bg_tab_crash() { 100, 5 ); - Assert.equal(browser.mIconURL, FAVICON, "Favicon is correctly set."); + await ImageTestUtils.assertEqualImage( + window, + browser.mIconURL, + FAVICON, + "Favicon is correctly set." + ); + await BrowserTestUtils.switchTab(gBrowser, originalTab); await BrowserTestUtils.crashFrame( browser, false /* shouldShowTabCrashPage */ ); - Assert.equal( + await ImageTestUtils.assertEqualImage( + window, browser.mIconURL, FAVICON, "Favicon is still set after crash." diff --git a/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_tab_favicons.js b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_tab_favicons.js @@ -3,6 +3,10 @@ "use strict"; +const { ImageTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/ImageTestUtils.sys.mjs" +); + /** * Check that about:debugging uses the favicon of tab targets as the icon of their debug * target item, and doesn't always use the default globe icon. @@ -14,10 +18,8 @@ const TAB_URL = "https://example.com/browser/devtools/client/aboutdebugging/" + "test/browser/test-tab-favicons.html"; -// The favicon in the page is re-encoded, with different results depending on zlib-rs usage. -const EXPECTED_FAVICON = AppConstants.USE_LIBZ_RS - ? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAXElEQVRYR+3SMQoAIAxD0fb+h9ZBEM3SKfwlTkISeEN7Va16Xt/feV9oyDsAHKCdaeDIA2AB+BEGgAO0Mw0ceQAsAD/CAHCAdqaBIw+ABeBHGAAO0M40cOQBoIANOAOf8d5vwtsAAAAASUVORK5CYII=" - : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAV0lEQVRYR+2UMQ4AIAgD4f+P1m6KcVQ7eMZBJCHNUcgWoTtOzoHeJan4dD4RYCewtvl2z3f1yx8CnhOwmxABdgLsAQjYTYgAOwGmAAJ2EyLAToAp+J5ABzgDn/EwCmG5AAAAAElFTkSuQmCC"; +const EXPECTED_FAVICON = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAV0lEQVRYR+2UMQ4AIAgD4f+P1m6KcVQ7eMZBJCHNUcgWoTtOzoHeJan4dD4RYCewtvl2z3f1yx8CnhOwmxABdgLsAQjYTYgAOwGmAAJ2EyLAToAp+J5ABzgDn/EwCmG5AAAAAElFTkSuQmCC"; add_task(async function () { const faviconTab = await addTab(TAB_URL, { background: true }); @@ -40,7 +42,8 @@ add_task(async function () { ".qa-debug-target-item-icon" ); - is( + await ImageTestUtils.assertEqualImage( + window, faviconTabIcon.src, EXPECTED_FAVICON, "The debug target item for the tab shows the favicon of the tab" diff --git a/testing/modules/ImageTestUtils.sys.mjs b/testing/modules/ImageTestUtils.sys.mjs @@ -0,0 +1,65 @@ +/* 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/. */ + +/** + * Provides testing functions working with images and image URLs. + */ + +import { Assert } from "resource://testing-common/Assert.sys.mjs"; + +export const ImageTestUtils = { + /** + * Assert that both provided image URLs are visually identical. + */ + async assertEqualImage(win, first, second, msg) { + const firstCanvas = await this.drawImageOnCanvas(win, first); + const secondCanvas = await this.drawImageOnCanvas(win, second); + + Assert.equal( + firstCanvas.width, + secondCanvas.width, + `${msg} - Both images have the same width` + ); + Assert.equal( + firstCanvas.height, + secondCanvas.height, + `${msg} - Both images have the same height` + ); + + const differences = win.windowUtils.compareCanvases( + firstCanvas, + secondCanvas, + {} + ); + Assert.equal(differences, 0, `${msg} - Both images are identical`); + }, + + drawImageOnCanvas(win, url) { + return new Promise((resolve, reject) => { + const img = new win.Image(); + + img.onload = function () { + // TODO: compareCanvases only works for the HTMLCanvasElement. + const canvas = win.document.createElementNS( + "http://www.w3.org/1999/xhtml", + "canvas" + ); + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + + const ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0); + + resolve(canvas); + }; + + img.onerror = function () { + reject(`error loading image ${url}`); + }; + + // Load the src image for drawing + img.src = url; + }); + }, +}; diff --git a/testing/modules/moz.build b/testing/modules/moz.build @@ -13,6 +13,7 @@ TESTING_JS_MODULES += [ "Assert.sys.mjs", "CoverageUtils.sys.mjs", "FileTestUtils.sys.mjs", + "ImageTestUtils.sys.mjs", "Mochia.js", "MockRegistrar.sys.mjs", "sinon-7.2.7.js",