diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /toolkit/components/aboutthirdparty/tests/browser | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/aboutthirdparty/tests/browser')
4 files changed, 469 insertions, 0 deletions
diff --git a/toolkit/components/aboutthirdparty/tests/browser/browser.ini b/toolkit/components/aboutthirdparty/tests/browser/browser.ini new file mode 100644 index 0000000000..ccb9c69fff --- /dev/null +++ b/toolkit/components/aboutthirdparty/tests/browser/browser.ini @@ -0,0 +1,7 @@ +[default] +head = head.js + +[browser_aboutthirdparty.js] +support-files = hello.zzz +skip-if = + os == "win" # Bug 1776048 diff --git a/toolkit/components/aboutthirdparty/tests/browser/browser_aboutthirdparty.js b/toolkit/components/aboutthirdparty/tests/browser/browser_aboutthirdparty.js new file mode 100644 index 0000000000..e4c8ca35ca --- /dev/null +++ b/toolkit/components/aboutthirdparty/tests/browser/browser_aboutthirdparty.js @@ -0,0 +1,317 @@ +/* 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/. */ + +// Return card containers matching a given name +function getCardsByName(aContainer, aLeafName) { + const matchedCards = []; + const allCards = aContainer.querySelectorAll(".card"); + for (const card of allCards) { + const nameLabel = card.querySelector(".module-name"); + if (nameLabel.textContent == aLeafName) { + matchedCards.push(card); + } + } + return matchedCards; +} + +function getDetailRow(aContainer, aLabel) { + return aContainer.querySelector(`[data-l10n-id=${aLabel}]`).parentElement; +} + +function verifyClipboardData(aModuleJson) { + Assert.ok( + aModuleJson.hasOwnProperty("blocked"), + "Clipboard data should have blocked property." + ); + const blocked = aModuleJson.blocked.filter( + x => x.name == kUserBlockedModuleName + ); + Assert.equal( + blocked.length, + 1, + "Blocked array should contain the blocked module one time." + ); + Assert.ok( + aModuleJson.hasOwnProperty("modules"), + "Clipboard data should have modules property" + ); + let aModuleArray = aModuleJson.modules; + const filtered = aModuleArray.filter(x => x.name == kExtensionModuleName); + Assert.equal(filtered.length, 1, "No duplicate data for the module."); + + const kDeletedPropertiesOfModule = [ + "application", + "dllFile", + "loadingOnMain", + "trustFlags", + ]; + const kDeletedPropertiesOfLoadingEvent = [ + "baseAddress", + "isDependent", + "mainThread", + "moduleIndex", + "processUptimeMS", + ]; + + for (const module of aModuleArray) { + for (const deletedProperty of kDeletedPropertiesOfModule) { + Assert.ok( + !module.hasOwnProperty(deletedProperty), + `The property \`${deletedProperty}\` is deleted.` + ); + } + + Assert.ok( + !module.hasOwnProperty("typeFlags") || module.typeFlags != 0, + "typeFlags does not exist or is non-zero." + ); + + for (const event of module.events) { + for (const deletedProperty of kDeletedPropertiesOfLoadingEvent) { + Assert.ok( + !event.hasOwnProperty(deletedProperty), + `The property \`${deletedProperty}\` is deleted.` + ); + } + } + } +} + +function verifyModuleSorting(compareFunc) { + const uninteresting = { + typeFlags: 0, + isCrasher: false, + loadingOnMain: 0, + }; + const crasherNotBlocked = { ...uninteresting, isCrasher: true }; + const crasherBlocked = { + ...uninteresting, + isCrasher: true, + typeFlags: Ci.nsIAboutThirdParty.ModuleType_BlockedByUserAtLaunch, + }; + const justBlocked = { + ...uninteresting, + typeFlags: Ci.nsIAboutThirdParty.ModuleType_BlockedByUserAtLaunch, + }; + const uninterestingButSlow = { + ...uninteresting, + loadingOnMain: 10, + }; + let modules = [ + uninteresting, + uninterestingButSlow, + crasherNotBlocked, + justBlocked, + crasherBlocked, + ]; + modules.sort(compareFunc); + Assert.equal( + JSON.stringify([ + crasherBlocked, + justBlocked, + crasherNotBlocked, + uninterestingButSlow, + uninteresting, + ]), + JSON.stringify(modules), + "Modules sort in expected order" + ); +} + +add_task(async () => { + registerCleanupFunction(() => { + unregisterAll(); + }); + await registerObject(); + registerExtensions(); + loadShellExtension(); + + await kATP.collectSystemInfo(); + Assert.equal( + kATP.lookupModuleType(kExtensionModuleName), + Ci.nsIAboutThirdParty.ModuleType_ShellExtension, + "lookupModuleType() returns a correct type " + + "after system info was collected." + ); + + await BrowserTestUtils.withNewTab("about:third-party", async browser => { + if (!content.fetchDataDone) { + const mainDiv = content.document.getElementById("main"); + await BrowserTestUtils.waitForMutationCondition( + mainDiv, + { childList: true }, + () => mainDiv.childElementCount > 0 + ); + Assert.ok(content.fetchDataDone, "onLoad() is completed."); + } + + const reload = content.document.getElementById("button-reload"); + if (!reload.hidden) { + reload.click(); + await BrowserTestUtils.waitForMutationCondition( + reload, + { attributes: true, attributeFilter: ["hidden"] }, + () => reload.hidden + ); + } + + Assert.ok( + content.document.getElementById("no-data").hidden, + "The no-data message is hidden." + ); + const blockedCards = getCardsByName( + content.document, + kUserBlockedModuleName + ); + Assert.equal( + blockedCards.length, + 1, + "Only one card matching the blocked module exists." + ); + const blockedCard = blockedCards[0]; + Assert.equal( + blockedCard.querySelectorAll(".button-block.module-blocked").length, + 1, + "The blocked module has a button indicating it is blocked" + ); + let blockedBlockButton = blockedCard.querySelector( + ".button-block.module-blocked" + ); + Assert.equal( + blockedBlockButton.getAttribute("data-l10n-id"), + "third-party-button-to-unblock", + "Button to block the module has correct title" + ); + blockedBlockButton.click(); + await BrowserTestUtils.promiseAlertDialogOpen("cancel"); + Assert.ok( + !blockedBlockButton.classList.contains("module-blocked"), + "After clicking to unblock a module, button should not have module-blocked class." + ); + Assert.equal( + blockedBlockButton.getAttribute("data-l10n-id"), + "third-party-button-to-block", + "After clicking to unblock a module, button should have correct title." + ); + // Restore this to blocked for later tests + blockedBlockButton.click(); + await BrowserTestUtils.promiseAlertDialogOpen("cancel"); + Assert.ok( + blockedBlockButton.classList.contains("module-blocked"), + "After clicking to block a module, button should have module-blocked class." + ); + Assert.equal( + blockedBlockButton.getAttribute("data-l10n-id"), + "third-party-button-to-unblock", + "After clicking to block a module, button should have correct title." + ); + + const cards = getCardsByName(content.document, kExtensionModuleName); + Assert.equal(cards.length, 1, "Only one card matching the module exists."); + const card = cards[0]; + + const blockButton = card.querySelector(".button-block"); + Assert.ok( + !blockButton.classList.contains("blocklist-disabled"), + "Button to block the module does not indicate the blocklist is disabled." + ); + Assert.ok( + !blockButton.classList.contains("module-blocked"), + "Button to block the module does not indicate the module is blocked." + ); + + Assert.ok( + card.querySelector(".image-warning").hidden, + "No warning sign for the module." + ); + Assert.equal( + card.querySelector(".image-unsigned").hidden, + false, + "The module is labeled as unsigned." + ); + Assert.equal( + card.querySelector(".tag-shellex").hidden, + false, + "The module is labeled as a shell extension." + ); + Assert.equal( + card.querySelector(".tag-ime").hidden, + true, + "The module is not labeled as an IME." + ); + + const versionRow = getDetailRow(card, "third-party-detail-version"); + Assert.equal( + versionRow.childNodes[1].textContent, + "1.2.3.4", + "The version matches a value in TestShellEx.rc." + ); + const vendorRow = getDetailRow(card, "third-party-detail-vendor"); + Assert.equal( + vendorRow.childNodes[1].textContent, + "Mozilla Corporation", + "The vendor name matches a value in TestShellEx.rc." + ); + const occurrencesRow = getDetailRow(card, "third-party-detail-occurrences"); + Assert.equal( + Number(occurrencesRow.childNodes[1].textContent), + 1, + "The module was loaded once." + ); + const durationRow = getDetailRow(card, "third-party-detail-duration"); + Assert.ok( + Number(durationRow.childNodes[1].textContent), + "The duration row shows a valid number." + ); + + const eventTable = card.querySelector(".event-table"); + const tableCells = eventTable.querySelectorAll("td"); + Assert.equal( + tableCells.length, + 3, + "The table has three cells as there is only one event." + ); + Assert.equal( + tableCells[0].querySelector(".process-type").getAttribute("data-l10n-id"), + "process-type-default", + "The module was loaded into the main process." + ); + Assert.ok( + Number(tableCells[0].querySelector(".process-id").textContent), + "A valid process ID is displayed." + ); + Assert.equal( + tableCells[1].querySelector(".event-duration").textContent, + durationRow.childNodes[1].textContent, + "The event's duration is the same as the average " + + "as there is only one event." + ); + Assert.equal( + tableCells[1].querySelector(".tag-background").hidden, + true, + "The icon handler is loaded in the main thread." + ); + Assert.equal( + tableCells[2].getAttribute("data-l10n-id"), + "third-party-status-loaded", + "The module was really loaded without being blocked." + ); + + const button = content.document.getElementById("button-copy-to-clipboard"); + button.click(); + + // Wait until copying is done and the button becomes clickable. + await BrowserTestUtils.waitForMutationCondition( + button, + { attributes: true }, + () => !button.disabled + ); + + const copiedJSON = JSON.parse(await navigator.clipboard.readText()); + Assert.ok(copiedJSON instanceof Object, "Data is an object."); + verifyClipboardData(copiedJSON); + + verifyModuleSorting(content.moduleCompareForDisplay); + }); +}); diff --git a/toolkit/components/aboutthirdparty/tests/browser/head.js b/toolkit/components/aboutthirdparty/tests/browser/head.js new file mode 100644 index 0000000000..eba3948046 --- /dev/null +++ b/toolkit/components/aboutthirdparty/tests/browser/head.js @@ -0,0 +1,144 @@ +/* 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/. */ + +"use strict"; + +const kClsidTestShellEx = "{10a9521e-0205-4cc7-93a1-62f30a9a54b3}"; +const kFriendlyName = "Minimum Shell Extension for Firefox testing"; +const kExtensionSubkeys = [".zzz\\shellex\\IconHandler"]; +const kExtensionModuleName = "TestShellEx.dll"; +const kUserBlockedModuleName = "TestDllBlocklist_UserBlocked.dll"; +const kFileFilterInDialog = "*.zzz"; +const kATP = Cc["@mozilla.org/about-thirdparty;1"].getService( + Ci.nsIAboutThirdParty +); + +function loadShellExtension() { + // This method call opens the file dialog and shows the support file + // "hello.zzz" in it, which loads TestShellEx.dll to show an icon + // for files with the .zzz extension. + kATP.openAndCloseFileDialogForTesting( + kExtensionModuleName, + getTestFilePath(""), + kFileFilterInDialog + ); +} + +async function registerObject() { + const reg = Cc["@mozilla.org/windows-registry-key;1"].createInstance( + Ci.nsIWindowsRegKey + ); + + reg.create( + Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + "Software\\Classes\\CLSID\\" + kClsidTestShellEx, + Ci.nsIWindowsRegKey.ACCESS_ALL + ); + + reg.writeStringValue("", kFriendlyName); + + const inprocServer = reg.createChild( + "InprocServer32", + Ci.nsIWindowsRegKey.ACCESS_ALL + ); + + const moduleFullPath = getTestFilePath(kExtensionModuleName); + Assert.ok(await IOUtils.exists(moduleFullPath), "The module file exists."); + + inprocServer.writeStringValue("", moduleFullPath); + inprocServer.writeStringValue("ThreadingModel", "Apartment"); + reg.close(); + + info("registerObject() done - " + moduleFullPath); +} + +function registerExtensions() { + for (const subkey of kExtensionSubkeys) { + const reg = Cc["@mozilla.org/windows-registry-key;1"].createInstance( + Ci.nsIWindowsRegKey + ); + reg.create( + Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + "Software\\Classes\\" + subkey, + Ci.nsIWindowsRegKey.ACCESS_ALL + ); + + let currentExtension = ""; + try { + // If the key was just created above, the default value does not exist, + // so readStringValue will throw NS_ERROR_FAILURE. + currentExtension = reg.readStringValue(""); + } catch (e) {} + + try { + if (!currentExtension) { + reg.writeStringValue("", kClsidTestShellEx); + } else if (currentExtension != kClsidTestShellEx) { + throw new Error( + `Another extension \`${currentExtension}\` has been registered.` + ); + } + } catch (e) { + throw new Error("Failed to register TestShellEx.dll: " + e); + } finally { + reg.close(); + } + } +} + +function unregisterAll() { + for (const subkey of kExtensionSubkeys) { + const reg = Cc["@mozilla.org/windows-registry-key;1"].createInstance( + Ci.nsIWindowsRegKey + ); + + try { + reg.open( + Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + "Software\\Classes\\" + subkey, + Ci.nsIWindowsRegKey.ACCESS_ALL + ); + + if (reg.readStringValue("") != kClsidTestShellEx) { + // If another extension is registered, don't overwrite it. + continue; + } + + // Set an empty string instead of deleting the key + // not to touch non-default values. + reg.writeStringValue("", ""); + } catch (e) { + info(`Failed to unregister \`${subkey}\`: ` + e); + } finally { + reg.close(); + } + } + + const reg = Cc["@mozilla.org/windows-registry-key;1"].createInstance( + Ci.nsIWindowsRegKey + ); + reg.open( + Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + "Software\\Classes\\CLSID", + Ci.nsIWindowsRegKey.ACCESS_ALL + ); + + try { + const child = reg.openChild( + kClsidTestShellEx, + Ci.nsIWindowsRegKey.ACCESS_ALL + ); + try { + child.removeChild("InprocServer32"); + } catch (e) { + } finally { + child.close(); + } + + reg.removeChild(kClsidTestShellEx); + } catch (e) { + } finally { + reg.close(); + } +} diff --git a/toolkit/components/aboutthirdparty/tests/browser/hello.zzz b/toolkit/components/aboutthirdparty/tests/browser/hello.zzz new file mode 100644 index 0000000000..e69ab604b3 --- /dev/null +++ b/toolkit/components/aboutthirdparty/tests/browser/hello.zzz @@ -0,0 +1 @@ +Showing this file on Windows Shell loads TestShellEx.dll.
|