Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  test_BrowserUtils.js

  Sprache: JAVA
 

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */


const { BrowserUtils } = ChromeUtils.importESModule(
  "resource://gre/modules/BrowserUtils.sys.mjs"
);

const { sinon } = ChromeUtils.importESModule(
  "resource://testing-common/Sinon.sys.mjs"
);

const { EnterprisePolicyTesting } = ChromeUtils.importESModule(
  "resource://testing-common/EnterprisePolicyTesting.sys.mjs"
);

const { Region } = ChromeUtils.importESModule(
  "resource://gre/modules/Region.sys.mjs"
);

const { updateAppInfo } = ChromeUtils.importESModule(
  "resource://testing-common/AppInfo.sys.mjs"
);

// Helper to run tests for specific regions
function setupRegions(home, current) {
  Region._setHomeRegion(home || "");
  Region._setCurrentRegion(current || "");
}

function setLanguage(language) {
  Services.locale.availableLocales = [language];
  Services.locale.requestedLocales = [language];
}

/**
 * Calls to this need to revert these changes by undoing them at the end of the test,
 * using:
 *
 *  await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
 */

async function setupEnterprisePolicy() {
  // set app info name as it's needed to set a policy and is not defined by default
  // in xpcshell tests
  updateAppInfo({
    name: "XPCShell",
  });

  // set up an arbitrary enterprise policy
  await EnterprisePolicyTesting.setupPolicyEngineWithJson({
    policies: {
      EnableTrackingProtection: {
        Value: true,
      },
    },
  });
}

add_task(async function test_shouldShowVPNPromo() {
  function setPromoEnabled(enabled) {
    Services.prefs.setBoolPref("browser.vpn_promo.enabled", enabled);
  }

  const allowedRegion = "US";
  const disallowedRegion = "SY";
  const illegalRegion = "CN";
  const unsupportedRegion = "LY";
  const regionNotInDefaultPref = "QQ";

  // Show promo when enabled in allowed regions
  setupRegions(allowedRegion, allowedRegion);
  Assert.ok(BrowserUtils.shouldShowVPNPromo());

  // Don't show when not enabled
  setPromoEnabled(false);
  Assert.ok(!BrowserUtils.shouldShowVPNPromo());

  // Don't show in disallowed home regions, even when enabled
  setPromoEnabled(true);
  setupRegions(disallowedRegion);
  Assert.ok(!BrowserUtils.shouldShowVPNPromo());

  // Don't show in illegal home regions, even when enabled
  setupRegions(illegalRegion);
  Assert.ok(!BrowserUtils.shouldShowVPNPromo());

  // Don't show in disallowed current regions, even when enabled
  setupRegions(allowedRegion, disallowedRegion);
  Assert.ok(!BrowserUtils.shouldShowVPNPromo());

  // Don't show in illegal current regions, even when enabled
  setupRegions(allowedRegion, illegalRegion);
  Assert.ok(!BrowserUtils.shouldShowVPNPromo());

  // Show if home region is supported, even if current region is not supported (but isn't disallowed or illegal)
  setupRegions(allowedRegion, unsupportedRegion);
  Assert.ok(BrowserUtils.shouldShowVPNPromo());

  // Show VPN if current region is supported, even if home region is unsupported (but isn't disallowed or illegal)
  setupRegions(unsupportedRegion, allowedRegion); // revert changes to regions
  Assert.ok(BrowserUtils.shouldShowVPNPromo());

  // Make sure we are getting the list of allowed regions from the right
  // place.
  setupRegions(regionNotInDefaultPref);
  Services.prefs.setStringPref(
    "browser.contentblocking.report.vpn_regions",
    "qq"
  );
  Assert.ok(BrowserUtils.shouldShowVPNPromo());
  Services.prefs.clearUserPref("browser.contentblocking.report.vpn_regions");

  if (AppConstants.platform !== "android") {
    // Services.policies isn't shipped on Android
    // Don't show VPN if there's an active enterprise policy
    setupRegions(allowedRegion, allowedRegion);
    await setupEnterprisePolicy();

    Assert.ok(!BrowserUtils.shouldShowVPNPromo());

    // revert policy changes made earlier
    await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
  }
});

add_task(async function test_sendToDeviceEmailsSupported() {
  const allowedLanguage = "en-US";
  const disallowedLanguage = "ar";

  // Return true if language is en-US
  setLanguage(allowedLanguage);
  Assert.ok(BrowserUtils.sendToDeviceEmailsSupported());

  // Return false if language is ar
  setLanguage(disallowedLanguage);
  Assert.ok(!BrowserUtils.sendToDeviceEmailsSupported());
});

add_task(async function test_shouldShowFocusPromo() {
  const allowedRegion = "US";
  const disallowedRegion = "CN";

  // Show promo when neither region is disallowed
  setupRegions(allowedRegion, allowedRegion);
  Assert.ok(BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.FOCUS));

  // Don't show when home region is disallowed
  setupRegions(disallowedRegion);
  Assert.ok(!BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.FOCUS));

  setupRegions(allowedRegion, allowedRegion);

  // Don't show when there is an enterprise policy active
  if (AppConstants.platform !== "android") {
    // Services.policies isn't shipped on Android
    await setupEnterprisePolicy();

    Assert.ok(!BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.FOCUS));

    // revert policy changes made earlier
    await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
  }

  // Don't show when promo disabled by pref
  Preferences.set("browser.promo.focus.enabled"false);
  Assert.ok(!BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.FOCUS));

  Preferences.resetBranch("browser.promo.focus");
});

add_task(async function test_shouldShowPinPromo() {
  Preferences.set("browser.promo.pin.enabled"true);
  // Show pin promo type by default when promo is enabled
  Assert.ok(BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.PIN));

  // Don't show when there is an enterprise policy active
  if (AppConstants.platform !== "android") {
    // Services.policies isn't shipped on Android
    await setupEnterprisePolicy();

    Assert.ok(!BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.PIN));

    // revert policy changes made earlier
    await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
  }

  // Don't show when promo disabled by pref
  Preferences.set("browser.promo.pin.enabled"false);
  Assert.ok(!BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.PIN));

  Preferences.resetBranch("browser.promo.pin");
});

add_task(async function test_shouldShowRelayPromo() {
  // This test assumes by default no uri is configured.
  Preferences.set("identity.fxaccounts.autoconfig.uri""");
  Assert.ok(BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.RELAY));

  // Don't show when there is an enterprise policy active
  if (AppConstants.platform !== "android") {
    // Services.policies isn't shipped on Android
    await setupEnterprisePolicy();

    Assert.ok(!BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.RELAY));

    // revert policy changes made earlier
    await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
  }

  // Don't show if a custom FxA instance is configured
  Preferences.set("identity.fxaccounts.autoconfig.uri""https://x");
  Assert.ok(!BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.RELAY));

  Preferences.reset("identity.fxaccounts.autoconfig.uri");
});

add_task(async function test_shouldShowCookieBannersPromo() {
  Preferences.set("browser.promo.cookiebanners.enabled"true);
  // Show cookie banners promo type by default when promo is enabled
  Assert.ok(
    BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.COOKIE_BANNERS)
  );

  // Don't show when promo disabled by pref
  Preferences.set("browser.promo.cookiebanners.enabled"false);
  Assert.ok(
    !BrowserUtils.shouldShowPromo(BrowserUtils.PromoType.COOKIE_BANNERS)
  );

  Preferences.resetBranch("browser.promo.cookiebanners");
});

add_task(function test_getShareableURL() {
  // Some test suites, specifically android, don't have this setup properly -- so we add it manually
  if (!Preferences.get("services.sync.engine.tabs.filteredSchemes")) {
    Preferences.set(
      "services.sync.engine.tabs.filteredSchemes",
      "about|resource|chrome|file|blob|moz-extension|data"
    );
  }
  // Empty shouldn't be sendable
  Assert.ok(!BrowserUtils.getShareableURL(""));
  // Valid
  let good = Services.io.newURI("https://mozilla.org");
  Assert.ok(BrowserUtils.getShareableURL(good).equals(good));
  // Invalid
  Assert.ok(
    !BrowserUtils.getShareableURL(Services.io.newURI("file://path/to/pdf.pdf"))
  );

  // Invalid
  Assert.ok(
    !BrowserUtils.getShareableURL(
      Services.io.newURI(
        "data:application/json;base64,ewogICJ0eXBlIjogIm1haW4i=="
      )
    )
  );

  // Reader mode:
  if (AppConstants.platform !== "android") {
    let readerUrl = Services.io.newURI(
      "about:reader?url=" + encodeURIComponent("http://foo.com/")
    );
    Assert.equal(
      BrowserUtils.getShareableURL(readerUrl).spec,
      "http://foo.com/"
    );
  }
});

/**
 * Verify that category manager calling modules are loaded on-demand,
 * and that caching doesn't break adding more modules as category entries
 * at runtime.
 */

add_task(async function test_callModulesFromCategory() {
  const MODULE1 = "resource://test/my_catman_1.sys.mjs";
  const MODULE2 = "resource://test/my_catman_2.sys.mjs";
  const CATEGORY = "test-modules-from-catman";
  const OBSTOPIC1 = CATEGORY + "-notification";
  const OBSTOPIC2 = CATEGORY + "-other-notification";

  // The two modules both fire different observer topics to allow us to ensure
  // they have been called. This helper just makes it easier to get only
  // that return value as a result of a promise, as `topicObserved` also
  // returns the "subject" of the observer notification, which we don't care about.
  let rvFromModule = topic =>
    TestUtils.topicObserved(topic).then(([_subj, data]) => data);

  // Start off with nothing in a category:
  Assert.equal(
    Cu.isESModuleLoaded(MODULE1),
    false,
    "First module should not be loaded."
  );
  let catEntries = Array.from(Services.catMan.enumerateCategory(CATEGORY));
  Assert.deepEqual(catEntries, [], "Should be no entries for this category.");

  try {
    // There's nothing in this category right now so this should be a no-op.
    BrowserUtils.callModulesFromCategory({ categoryName: CATEGORY }, "Hello");
  } catch (ex) {
    Assert.ok(false, `Should not have thrown but received an exception ${ex}`);
  }

  // Now add an item, check that calling it now works.
  //
  // Note that category manager observer notifications are async (they get
  // dispatched as runnables) and so we have to wait for it to make sure that
  // BrowserUtils has had a chance of being told new entries have arrived.
  let catManUpdated = TestUtils.topicObserved("xpcom-category-entry-added");

  Services.catMan.addCategoryEntry(
    CATEGORY,
    MODULE1,
    `Module1.test`,
    false,
    false
  );
  catEntries = Array.from(Services.catMan.enumerateCategory(CATEGORY));
  Assert.equal(catEntries.length, 1);

  // See note above.
  await catManUpdated;

  Assert.equal(
    Cu.isESModuleLoaded(MODULE1),
    false,
    "First module should still not be loaded."
  );

  // This entry will cause an observer topic to notify, so ensure that happens.
  let moduleResult = rvFromModule(OBSTOPIC1);
  BrowserUtils.callModulesFromCategory({ categoryName: CATEGORY }, "Hello");
  Assert.equal(
    Cu.isESModuleLoaded(MODULE1),
    true,
    "First module should be loaded sync."
  );
  Assert.equal("Hello", await moduleResult, "Should have been called.");

  // Now add another item, check that both are called.
  catManUpdated = TestUtils.topicObserved("xpcom-category-entry-added");
  Services.catMan.addCategoryEntry(
    CATEGORY,
    MODULE2,
    `Module2.othertest`,
    false,
    false
  );
  await catManUpdated;

  moduleResult = Promise.all([
    rvFromModule(OBSTOPIC1),
    rvFromModule(OBSTOPIC2),
  ]);

  BrowserUtils.callModulesFromCategory({ categoryName: CATEGORY }, "Hello");
  Assert.deepEqual(
    ["Hello""Hello"],
    await moduleResult,
    "Both modules should have been called."
  );

  // Now remove the first module again, check that only the second one notifies.
  catManUpdated = TestUtils.topicObserved("xpcom-category-entry-removed");
  Services.catMan.deleteCategoryEntry(CATEGORY, MODULE1, false);
  await catManUpdated;
  let ob = () => Assert.ok(false"I shouldn't be called.");
  Services.obs.addObserver(ob, OBSTOPIC1);

  moduleResult = rvFromModule(OBSTOPIC2);
  BrowserUtils.callModulesFromCategory({ categoryName: CATEGORY }, "Hello");
  Assert.equal(
    "Hello",
    await moduleResult,
    "Second module should still be called."
  );

  let idleResult = null;
  let idlePromise = TestUtils.topicObserved(OBSTOPIC2).then(([_subj, data]) => {
    idleResult = data;
    return data;
  });
  BrowserUtils.callModulesFromCategory(
    { categoryName: CATEGORY, idleDispatch: true },
    "Hello"
  );
  Assert.equal(idleResult, null"Idle calls should not happen immediately.");
  Assert.equal("Hello", await idlePromise, "Idle calls should run eventually.");

  Services.obs.removeObserver(ob, OBSTOPIC1);

  // Now clean up our category for later tests.
  Services.catMan.deleteCategory(CATEGORY);
});

// Test that errors are reported but do not throw at the callsite,
// and that custom error handlers are invoked.
add_task(async function test_callModulesFromCategory_errors() {
  const OTHER_CAT = "someothercat";
  const MODULE1 = "resource://test/my_catman_1.sys.mjs";

  // Add an item that doesn't exist, and check that although we report errors,
  // the callsite doesn't throw.
  let catManUpdated = TestUtils.topicObserved("xpcom-category-entry-added");
  Services.catMan.addCategoryEntry(
    OTHER_CAT,
    MODULE1,
    `Module1.nonExistantFunction`,
    false,
    false
  );
  await catManUpdated;
  let catEntries = Array.from(Services.catMan.enumerateCategory(OTHER_CAT));
  Assert.equal(catEntries.length, 1);

  let consolePromise = TestUtils.consoleMessageObserved(m => {
    let firstArg = m.wrappedJSObject.arguments?.[0]?.message;
    return typeof firstArg == "string" && firstArg.includes("not a function");
  });
  BrowserUtils.callModulesFromCategory(
    {
      categoryName: OTHER_CAT,
    },
    "Hello"
  );
  let reportedError = await consolePromise;
  let firstArg = reportedError.wrappedJSObject.arguments?.[0]?.message;
  Assert.stringContains(
    firstArg,
    MODULE1,
    "Error message should include module URL."
  );
  Services.catMan.deleteCategoryEntry(OTHER_CAT, MODULE1, false);

  // Check that custom exception handling from extant methods works:
  catManUpdated = TestUtils.topicObserved("xpcom-category-entry-added");
  Services.catMan.addCategoryEntry(
    OTHER_CAT,
    MODULE1,
    `Module1.throwingFunction`,
    false,
    false
  );
  await catManUpdated;
  Assert.equal(catEntries.length, 1);
  let exHandler = Promise.withResolvers();
  BrowserUtils.callModulesFromCategory({
    categoryName: OTHER_CAT,
    failureHandler: exHandler.resolve,
  });
  let caughtException = await exHandler.promise;
  Assert.stringContains(
    caughtException.message,
    "Uh oh",
    "Exceptions should be handled."
  );

  // Now clean up our category for later tests.
  Services.catMan.deleteCategory(OTHER_CAT);
});

/**
 * Test that callModulesFromCategory returns a Promise that resolves when all
 * category tasks have settled.
 */

add_task(async function test_callModulesFromCategory_returns_promise() {
  const CATEGORY = "test-modules-from-catman";
  const MODULE1 = "resource://test/my_catman_1.sys.mjs";
  const OBSTOPIC1 = CATEGORY + "-notification";

  let catManUpdated = TestUtils.topicObserved("xpcom-category-entry-added");
  Services.catMan.addCategoryEntry(
    CATEGORY,
    MODULE1,
    `Module1.test`,
    false,
    false
  );
  await catManUpdated;

  let moduleResult = TestUtils.topicObserved(OBSTOPIC1).then(
    ([_subj, data]) => data
  );

  let result = BrowserUtils.callModulesFromCategory(
    { categoryName: CATEGORY },
    "Hello"
  );

  Assert.ok(result.then, "Should return a Promise");

  let settledResults = await result;
  Assert.ok(Array.isArray(settledResults), "Should return an array of results");
  Assert.equal(settledResults.length, 1"Should have one result");
  Assert.equal(
    settledResults[0].status,
    "fulfilled",
    "Task should have been fulfilled"
  );

  Assert.equal(await moduleResult, "Hello""Module should have been called");

  // Now clean up our category for later tests.
  Services.catMan.deleteCategory(CATEGORY);
});

// Test a category with both a plain .js entry and an ESM entry, for both
// single-window and multi-window scenarios.
add_task(async function test_callModulesFromCategory_multiple_window() {
  const CATEGORY = "test-js-global-catman";
  // A fake .js URL — the file doesn't need to exist since we rely on
  // jsGlobal having the object already (via lazy getter in production).
  const MODULE_JS = "chrome://browser/content/fake-catman-test.js";
  const MODULE_ESM = "resource://test/my_catman_1.sys.mjs";
  const OBSTOPIC = "test-modules-from-catman-notification";

  let catManUpdated = TestUtils.topicObserved("xpcom-category-entry-added");
  Services.catMan.addCategoryEntry(
    CATEGORY,
    MODULE_JS,
    "FakeObj.doThing",
    false,
    false
  );
  await catManUpdated;

  catManUpdated = TestUtils.topicObserved("xpcom-category-entry-added");
  Services.catMan.addCategoryEntry(
    CATEGORY,
    MODULE_ESM,
    "Module1.test",
    false,
    false
  );
  await catManUpdated;

  let sandbox = sinon.createSandbox();

  // Window 1: both the .js and ESM entries should be called.
  let fakeGlobal1 = { FakeObj: { doThing: sandbox.spy() } };

  let esmResult = TestUtils.topicObserved(OBSTOPIC).then(([, data]) => data);
  BrowserUtils.callModulesFromCategory(
    { categoryName: CATEGORY, jsGlobal: fakeGlobal1 },
    "window1"
  );
  sinon.assert.calledOnce(fakeGlobal1.FakeObj.doThing);
  sinon.assert.calledWithExactly(fakeGlobal1.FakeObj.doThing, "window1");
  Assert.equal(await esmResult, "window1""ESM entry called for window 1.");

  // Window 2 (multi-window): the .js entry must use the new jsGlobal, while
  // the ESM entry continues to use the same singleton module instance.
  let fakeGlobal2 = { FakeObj: { doThing: sandbox.spy() } };

  esmResult = TestUtils.topicObserved(OBSTOPIC).then(([, data]) => data);
  BrowserUtils.callModulesFromCategory(
    { categoryName: CATEGORY, jsGlobal: fakeGlobal2 },
    "window2"
  );
  sinon.assert.calledOnce(fakeGlobal2.FakeObj.doThing);
  sinon.assert.calledWithExactly(fakeGlobal2.FakeObj.doThing, "window2");
  sinon.assert.calledOnce(fakeGlobal1.FakeObj.doThing); // not called again
  Assert.equal(await esmResult, "window2""ESM entry called for window 2.");

  sandbox.restore();
  Services.catMan.deleteCategory(CATEGORY);
});

// Test error paths for the jsGlobal / plain-.js-script code path.
add_task(async function test_callModulesFromCategory_jsGlobal_errors() {
  const CATEGORY = "test-js-global-catman-errors";
  const MODULE = "chrome://browser/content/fake-catman-test.js";

  let catManUpdated = TestUtils.topicObserved("xpcom-category-entry-added");
  Services.catMan.addCategoryEntry(
    CATEGORY,
    MODULE,
    "FakeObj.doThing",
    false,
    false
  );
  await catManUpdated;

  // Omitting jsGlobal for a .js entry should log an error.
  let consolePromise = TestUtils.consoleMessageObserved(m => {
    let firstArg = m.wrappedJSObject.arguments?.[0];
    return typeof firstArg == "string" && firstArg.includes(CATEGORY);
  });
  BrowserUtils.callModulesFromCategory({ categoryName: CATEGORY }, "hello");
  await consolePromise;

  // Providing a jsGlobal that lacks the expected object should log an error.
  consolePromise = TestUtils.consoleMessageObserved(m => {
    let firstArg = m.wrappedJSObject.arguments?.[0];
    return typeof firstArg == "string" && firstArg.includes(CATEGORY);
  });
  BrowserUtils.callModulesFromCategory(
    { categoryName: CATEGORY, jsGlobal: {} },
    "hello"
  );
  await consolePromise;

  Services.catMan.deleteCategory(CATEGORY);
});

add_task(async function test_willLoadInBackground() {
  const TEST_DATA = [
    // where: "tab" and loadInBackgroundPref is on.
    {
      loadInBackgroundPref: false,
      where: "tab",
      expected: false,
    },
    {
      loadInBackgroundPref: false,
      where: "tab",
      params: { inBackground: true },
      expected: true,
    },
    {
      loadInBackgroundPref: false,
      where: "tab",
      params: { inBackground: false },
      expected: false,
    },
    {
      loadInBackgroundPref: false,
      where: "tab",
      params: { forceForeground: true },
      expected: false,
    },
    {
      loadInBackgroundPref: false,
      where: "tab",
      params: { forceForeground: false },
      expected: false,
    },
    // where: "tab" and loadInBackgroundPref is off.
    {
      loadInBackgroundPref: true,
      where: "tab",
      expected: true,
    },
    {
      loadInBackgroundPref: true,
      where: "tab",
      params: { inBackground: true },
      expected: true,
    },
    {
      loadInBackgroundPref: true,
      where: "tab",
      params: { inBackground: false },
      expected: false,
    },
    {
      loadInBackgroundPref: true,
      where: "tab",
      params: { forceForeground: true },
      expected: false,
    },
    {
      loadInBackgroundPref: true,
      where: "tab",
      params: { forceForeground: false },
      expected: true,
    },
    // where: "tabshifted" and loadInBackgroundPref is on.
    {
      loadInBackgroundPref: false,
      where: "tabshifted",
      expected: true,
    },
    {
      loadInBackgroundPref: false,
      where: "tabshifted",
      params: { inBackground: true },
      expected: false,
    },
    {
      loadInBackgroundPref: false,
      where: "tabshifted",
      params: { inBackground: false },
      expected: true,
    },
    {
      loadInBackgroundPref: false,
      where: "tabshifted",
      params: { forceForeground: true },
      expected: true,
    },
    {
      loadInBackgroundPref: false,
      where: "tabshifted",
      params: { forceForeground: false },
      expected: true,
    },
    // where: "tabshifted" and loadInBackgroundPref is off.
    {
      loadInBackgroundPref: true,
      where: "tabshifted",
      expected: false,
    },
    {
      loadInBackgroundPref: true,
      where: "tabshifted",
      params: { inBackground: true },
      expected: false,
    },
    {
      loadInBackgroundPref: true,
      where: "tabshifted",
      params: { inBackground: false },
      expected: true,
    },
    {
      loadInBackgroundPref: true,
      where: "tabshifted",
      params: { forceForeground: true },
      expected: true,
    },
    {
      loadInBackgroundPref: true,
      where: "tabshifted",
      params: { forceForeground: false },
      expected: false,
    },
    // where: other,
    {
      loadInBackgroundPref: true,
      where: "current",
      params: { inBackground: true },
      expected: false,
    },
  ];

  for (const { loadInBackgroundPref, where, params, expected } of TEST_DATA) {
    info(
      `Test for ${JSON.stringify({ loadInBackgroundPref, where, params, expected })}`
    );
    Services.prefs.setBoolPref(
      "browser.tabs.loadInBackground",
      loadInBackgroundPref
    );

    Assert.equal(BrowserUtils.willLoadInBackground(where, params), expected);

    Services.prefs.clearUserPref("browser.tabs.loadInBackground");
  }
});

Messung V0.5 in Prozent
C=86 H=94 G=89

¤ Dauer der Verarbeitung: 0.8 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002