/* 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-module", "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-module", "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-module", "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); }); });