Raw File
test_app_update.html
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=826058
-->
<head>
  <meta charset="utf-8">
  <title>Test for Bug 826058</title>
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
  <script type="application/javascript;version=1.7">

  /** Test for Bug 826058 **/

  SimpleTest.waitForExplicitFinish();

  var gBaseURL = 'http://test/tests/dom/apps/tests/';
  var gHostedManifestURL = gBaseURL + 'file_app.sjs?apptype=hosted&getmanifest=true';
  var gCachedManifestURL = gBaseURL + 'file_app.sjs?apptype=cached&getmanifest=true';
  var gGenerator = runTest();
  var launchableValue = undefined;

  function go() {
    SpecialPowers.pushPermissions(
      [{ "type": "browser", "allow": 1, "context": document },
       { "type": "embed-apps", "allow": 1, "context": document },
       { "type": "webapps-manage", "allow": 1, "context": document }],
      function() { gGenerator.next() });
  }

  function continueTest() {
    try { gGenerator.next(); }
    catch (e) { dump("Got exception: " + e + "\n"); }
  }

  function mozAppsError() {
    ok(false, "mozApps error: " + this.error.name);
    finish();
  }

  function xhrError(event, url) {
    var xhr = event.target;
    ok(false, "XHR error loading " + url + ": " + xhr.status + " - " +
              xhr.statusText);
    finish();
  }

  function xhrAbort(url) {
    ok(false, "XHR abort loading " + url);
    finish();
  }

  function runTest() {
    // Set up.

    launchableValue = SpecialPowers.setAllAppsLaunchable(true);
    SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);

    // Test Bug 927699 - navigator.mozApps.install(url) lets NS_ERROR_FAILURE
    //                   onto the web
    var request = navigator.mozApps.install("");
    request.onerror = function() {
      ok(request.error.name == "INVALID_URL", "Got expected INVALID_URL");
      continueTest();
    };
    request.onsuccess = mozAppsError;
    yield undefined;

    setAppVersion(1, continueTest);
    yield undefined;
    SpecialPowers.autoConfirmAppInstall(continueTest);
    yield undefined;

    // Load the app, uninstalled.
    checkAppState(null, false, 1, continueTest);
    yield undefined;

    // Bump the version and install the app.
    setAppVersion(2, continueTest);
    yield undefined;

    request = navigator.mozApps.install(gHostedManifestURL);
    request.onerror = mozAppsError;
    request.onsuccess = continueTest;
    yield undefined;
    var app = request.result;
    ok(app, "App is non-null");
    ok(app.manifest.description == "Updated even faster than Firefox, just to annoy slashdotters.",
       "Manifest is HTML-sanitized");

    // Check the app a few times.
    checkAppState(app, true, 2, continueTest);
    yield undefined;
    checkAppState(app, true, 2, continueTest);
    yield undefined;

    // Bump the version and check the app again. The app is not cached, so the
    // version bump takes effect.
    setAppVersion(3, continueTest);
    yield undefined;
    checkAppState(app, true, 3, continueTest);
    yield undefined;

    // check for update
    var icons = app.manifest.icons;
    var oldIcon = icons[Object.keys(icons)[0]];
    var oldUpdateTime = app.updateTime;
    setAppIcon('new_icon', continueTest);
    yield undefined;

    app.ondownloadavailable = function() {
      ok(false, 'Got a downloadavailable event for non-cached hosted apps');
    };

    app.ondownloadapplied = function() {
      ok(true, 'Got a downloadapplied when checking for update');
      app.ondownloadapplied = app.ondownloadavailable = null;
      continueTest();
    };
    app.checkForUpdate();
    yield undefined;

    icons = app.manifest.icons;
    var newIcon = icons[Object.keys(icons)[0]];
    var newUpdateTime = app.updateTime;
    isnot(oldIcon, newIcon, 'The icon should be updated');
    isnot(oldUpdateTime, newUpdateTime, 'The update time should be updated');

    // Uninstall the app.
    request = navigator.mozApps.mgmt.uninstall(app);
    request.onerror = mozAppsError;
    request.onsuccess = continueTest;
    yield undefined;

    // Check the uninstalled app.
    checkAppState(app, false, 3, continueTest);
    yield undefined;

    // Install the cached app.
    setAppVersion(3, continueTest);
    yield undefined;
    ok(true, "Installing cached app");
    var request = navigator.mozApps.install(gCachedManifestURL);
    request.onerror = mozAppsError;
    request.onsuccess = continueTest;
    yield undefined;
    var app = request.result;
    ok(app, "App is non-null");
    if (app.installState == "pending") {
      ok(true, "App is pending. Waiting for progress");
      app.onprogress = function() ok(true, "Got download progress");
      app.ondownloadsuccess = continueTest;
      app.ondownloaderror = mozAppsError;
      yield undefined;
    }
    is(app.installState, "installed", "App is installed");

    // Check the cached app.
    checkAppState(app, true, 3, continueTest);
    yield undefined;

    // Check for updates. The current infrastructure always returns a new appcache
    // manifest, so there should always be an update.
    var lastCheck = app.lastUpdateCheck;
    ok(true, "Setting callbacks");
    app.ondownloadapplied = function() ok(true, "downloadapplied fired.");
    app.ondownloadavailable = function() ok(false, "downloadavailable fired");
    ok(true, "Checking for updates");
    var request = app.checkForUpdate();
    request.onerror = mozAppsError;
    request.onsuccess = continueTest;
    yield undefined;
    todo(app.lastUpdateCheck > lastCheck, "lastUpdateCheck updated appropriately");


    // Uninstall the app.
    request = navigator.mozApps.mgmt.uninstall(app);
    request.onerror = mozAppsError;
    request.onsuccess = continueTest;
    yield undefined;
    ok(true, "Uninstalled app");

    // Check the uninstalled app.
    checkAppState(app, false, 3, continueTest);
    yield undefined;

    // All done.
    ok(true, "All done");
    finish();
  }

  function setAppVersion(version, cb) {
    var xhr = new XMLHttpRequest();
    var url = gBaseURL + 'file_app.sjs?setVersion=' + version;
    xhr.addEventListener("load", function() { is(xhr.responseText, "OK", "setAppVersion OK"); cb(); });
    xhr.addEventListener("error", event => xhrError(event, url));
    xhr.addEventListener("abort", event => xhrAbort(url));
    xhr.open('GET', url, true);
    xhr.send();
  }

  function setAppIcon(icon, cb) {
    var xhr = new XMLHttpRequest();
    var url = gBaseURL + 'file_app.sjs?setIcon=' + icon;
    xhr.addEventListener("load", function() { is(xhr.responseText, "OK", "setAppIcon OK"); cb(); });
    xhr.addEventListener("error", event => xhrError(event, url));
    xhr.addEventListener("abort", event => xhrAbort(url));
    xhr.open('GET', url, true);
    xhr.send();
  }

  // This function checks the state of an installed app. It does the following:
  //
  // * Check various state on the app object itself.
  // * Launch the app.
  // * Listen for messages from the app, verifying state.
  // * Close the app.
  // * Invoke the callback.
  function checkAppState(app, installed, version, cb) {
    // Check state on the app object.
    if (installed)
      is(app.installState, "installed", "Checking installed app");
    else
      ok(true, "Checking uninstalled app");

    // Set up the app. We need to set the attributes before the app is inserted
    // into the DOM.
    var ifr = document.createElement('iframe');
    ifr.setAttribute('mozbrowser', 'true');
    ifr.setAttribute('mozapp', app ? app.manifestURL : gHostedManifestURL);
    ifr.setAttribute('src', getAppURL(app));
    var domParent = document.getElementById('container');

    // Set us up to listen for messages from the app.
    var listener = function(e) {
      var message = e.detail.message;
      if (/OK/.exec(message)) {
        ok(true, "Message from app: " + message);
      } else if (/KO/.exec(message)) {
        ok(false, "Message from app: " + message);
      } else if (/IS_INSTALLED/.exec(message)) {
        ok(installed, "App is installed");
      } else if (/NOT_INSTALLED/.exec(message)) {
        ok(!installed, "App is not installed");
      } else if (/VERSION/.exec(message)) {
        is(message, "VERSION: MyWebApp v" + version, "Version should be correct");
      } else if (/DONE/.exec(message)) {
        ok(true, "Messaging from app complete");
        ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
        domParent.removeChild(ifr);
        cb();
      }
    }

    // This event is triggered when the app calls "alert".
    ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);

    // Add the iframe to the DOM, triggering the launch.
    domParent.appendChild(ifr);
  }

  // Returns that appropriate path for the app associated with the manifest,
  // or the base sjs file if app is null.
  function getAppURL(app) {
    if (!app)
      return gBaseURL + "file_app.sjs?apptype=hosted";
    return app.origin + app.manifest.launch_path;
  }

  function finish() {
    SpecialPowers.clearUserPref("dom.mozBrowserFramesEnabled");
    //SpecialPowers.setAllAppsLaunchable(launchableValue);
    SimpleTest.finish();
  }

  function doReload() {
    window.location.reload(true);
  }

  </script>
</head>
<body onload="go()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=826058">Mozilla Bug 826058</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=863337">Mozilla Bug 863337</a>
<p id="display"></p>
<div id="content" style="display: none">

</div>
<pre id="test">
</pre>
<div id="container"></div>
<button onclick="doReload()">Reload Page</button>
</body>
</html>
back to top