Toggle passed checks Toggle failed checks Toggle todo checks
Passed: 7
Failed: 38
Todo: 0
failed | navigator.mozApps.QueryInterfacenavigator.mozApps.enumeratenavigator.mozApps.enumerateAllnavigator.mozApps.installnavigator.mozApps.launchnavigator.mozApps.uninstall
passed |
passed |
failed | Error: navigator.mozApps.mgmt is undefined
passed |
passed |
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: Not enough arguments [mozIDOMApplicationRegistry.install]
failed | Error: navigator.mozApps.setMockResponse is not a functionError: wait(called:Spy('setMockResponse')) has timed out
failed | Error: pending is undefined
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: navigator.mozApps.setMockResponse is not a functionError: wait(called:Spy('setMockResponse')) has timed out
failed | Error: pending is undefined
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: navigator.mozApps.getInstalled is not a function
failed | Error: navigator.mozApps.getSelf is not a function
failed | Error: Channel is not defined
failed | Error: pending is undefined
failed | Error: pending is undefined
failed | Error: pending is undefined
failed | Error: pending is undefined
failed | Error: Channel is not defined
failed | Error: chan is undefined
failed | Error: chan is undefined
failed | Error: chan is undefined
failed | Error: navigator.mozApps.getInstalled is not a function
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: Channel is not defined
failed | Error: chan is undefined
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: pending is undefined
failed | Error: navigator.mozApps.mgmt is undefined
passed |
passed |
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: navigator.mozApps.mgmt is undefined
passed |
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: navigator.mozApps.mgmt is undefined
failed | Error: pending is undefined
failed | Error: lastPending is null
failed | Error: Channel is not defined
failed | Error: chan is undefined

Dummy Target

Failed example:
// We'll show all the methods we're testing
var arr = [];
function iterateMethods(label, root, suppress) {
  for (var f in root) {
      if (suppress && suppress.indexOf(f) != -1)
          continue;
      if (typeof root[f] === 'function')
          arr.push(label + f);
  }
}

iterateMethods("navigator.mozApps.", navigator.mozApps, ['setApplicationChooser', 'setRepoOrigin', 'setMockResponse']);
iterateMethods("navigator.mozApps.mgmt.", navigator.mozApps.mgmt);

arr = arr.sort();
for (var i = 0; i < arr.length; i++) writeln(arr[i]);
Expected:
navigator.mozApps.getInstalled
navigator.mozApps.getSelf
navigator.mozApps.install...
navigator.mozApps.mgmt.addEventListener
navigator.mozApps.mgmt.getAll
navigator.mozApps.mgmt.removeEventListener...

Got:
navigator.mozApps.QueryInterface
navigator.mozApps.enumerate
navigator.mozApps.enumerateAll
navigator.mozApps.install
navigator.mozApps.launch
navigator.mozApps.uninstall

Failed example:
// Out of curiosity we'll see what's installed:
spyPending(navigator.mozApps.mgmt.getAll());
Expected:
onsuccess: ...
Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
uninstallAll()();
Expected:
(nothing)
Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
spyPending(navigator.mozApps.mgmt.getAll());
Expected:
onsuccess: []

Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
navigator.mozApps.install();
Expected:
Error: install missing required url argument

Got:
Error: Not enough arguments [mozIDOMApplicationRegistry.install]

Failed example:
navigator.mozApps.setMockResponse(true, Spy('setMockResponse', {wait: true}));
Expected:
setMockResponse()
Got:
Error: navigator.mozApps.setMockResponse is not a function
Error: wait(called:Spy('setMockResponse')) has timed out

Failed example:
spyPending(navigator.mozApps.install(
  SERVERS['basic_app'] + "/manifest.webapp",
  null));
Expected:
onsuccess: {
  installOrigin: "http://?:?",
  installTime: ?,
  manifest: {installs_allowed_from: ["*"], name: "Super Crazy Basic App"},
  manifestURL: "http://?:?/manifest.webapp",
  origin: "http://?:?",
  receipts: null
}
Got:
Error: pending is undefined

Failed example:
spyPending(navigator.mozApps.mgmt.getAll());
Expected:
onsuccess: [
      {
        installOrigin: "http://?:?",
        installTime: ?,
        manifest: {installs_allowed_from: ["*"], name: "Super Crazy Basic App"},
        manifestURL: "http://?:?/manifest.webapp",
        origin: "http://?:?",
        receipts: null
      }
    ]

Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
navigator.mozApps.setMockResponse(true, Spy('setMockResponse', {wait: true}));
Expected:
setMockResponse()
Got:
Error: navigator.mozApps.setMockResponse is not a function
Error: wait(called:Spy('setMockResponse')) has timed out

Failed example:
spyPending(navigator.mozApps.install(
  SERVERS['basic_app'] + "/manifest2.webapp",
  null));
Expected:
onsuccess: {...}
Got:
Error: pending is undefined

Failed example:
spyPending(navigator.mozApps.mgmt.getAll());
Expected:
onsuccess: [
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {installs_allowed_from: ["*"], name: "Wild and Crazy Basic App"},
    manifestURL: "http://?:?/manifest2.webapp",
    origin: "http://...:...",
    receipts: null
  }
]

Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
spyPending(navigator.mozApps.getInstalled());
Expected:
onsuccess: [
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {installs_allowed_from: ["*"], name: "Wild and Crazy Basic App"},
    manifestURL: "http://?:?/manifest2.webapp",
    origin: "http://...:...",
    receipts: null
  }
]

Got:
Error: navigator.mozApps.getInstalled is not a function

Failed example:
spyPending(navigator.mozApps.getSelf());
Expected:
onsuccess: null

Got:
Error: navigator.mozApps.getSelf is not a function

Failed example:
var chan = embedIFrameAndStartChannel(SERVERS['basic_app'] + "/include.html");
chan.call(buildJSChanArgs("getSelf", true));
Expected:
success({
  installOrigin: "http://...:...",
  installTime: ...,
  manifest: {installs_allowed_from: ["*"], name: "Wild and Crazy Basic App"},
  manifestURL: "http://?:?/manifest2.webapp",
  origin: "http://...:...",
  receipts: null
})

Got:
Error: Channel is not defined

Failed example:
spyPending(navigator.mozApps.install(
  SERVERS['json_syntax_error'] + "/manifest.webapp",
  null));
Expected:
onerror: MANIFEST_PARSE_ERROR

Got:
Error: pending is undefined

Failed example:
spyPending(navigator.mozApps.install(
  SERVERS['missing_required_field'] + "/manifest.webapp",
  null));
Expected:
onerror: INVALID_MANIFEST

Got:
Error: pending is undefined

Failed example:
spyPending(navigator.mozApps.install(
  SERVERS['bad_content_type'] + "/manifest.json",
  null));
Expected:
onerror: INVALID_MANIFEST

Got:
Error: pending is undefined

Failed example:
spyPending(navigator.mozApps.install(
  SERVERS['no_delegated_install'] + "/manifest.webapp",
  null));
Expected:
onerror: PERMISSION_DENIED

Got:
Error: pending is undefined

Failed example:
var chan = embedIFrameAndStartChannel(SERVERS['no_delegated_install'] + "/include.html");
Expected:
(nothing)
Got:
Error: Channel is not defined

Failed example:
chan.call(buildJSChanArgs("install", true));
Expected:
success()
Got:
Error: chan is undefined

Failed example:
// now getInstalled should show that we're installed
chan.call(buildJSChanArgs("getSelf", true));
Expected:
success({
  installOrigin: "http://...:...",
  installTime: ...,
  manifest: {name: "An application which does not grant permission for any other origin to install it"},
  manifestURL: "http://?:?/manifest.webapp",
  origin: "http://...:...",
  receipts: null
})
Got:
Error: chan is undefined

Failed example:
// and getInstalledBy should show that same result
chan.call(buildJSChanArgs("getInstalled", true));
Expected:
success([
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {name: "An application which does not grant permission for any other origin to install it"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://...:...",
    receipts: null
  }
])

Got:
Error: chan is undefined

Failed example:
spyPending(navigator.mozApps.getInstalled());
Expected:
onsuccess: [
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {installs_allowed_from: ["*"], name: "Wild and Crazy Basic App"},
    manifestURL: "http://?:?/manifest2.webapp",
    origin: "http://...:...",
    receipts: null
  }
]

Got:
Error: navigator.mozApps.getInstalled is not a function

Failed example:
var spy = Spy('list');
var pendingGetAll = navigator.mozApps.mgmt.getAll();
pendingGetAll.onsuccess = function() {
  for (var i=0; i<this.result.length; i++) {
    writeln('Origin: ', this.result[i].origin);
  }
  spy.func(i);
};
spy.wait();
Expected:
Origin: ...
Origin: ...
list(2)

Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
// first let's add an iframe with the child to the document */
var chan = embedIFrameAndStartChannel(SERVERS['no_mgmt_api_off_repo_origin'] + "/include.html");
Expected:
(nothing)
Got:
Error: Channel is not defined

Failed example:
// Note the exact error here is not so clear, so we kind of punt:
chan.call(buildJSChanArgs("getAll", false));
Expected:
error("...")

Got:
Error: chan is undefined

Failed example:
var pendingGetAll1 = navigator.mozApps.mgmt.getAll();
pendingGetAll1.onsuccess = function() {
  spyPending(this.result[0].uninstall(), 'firstUninstall', true);
  spyPending(this.result[0].uninstall(), 'secondUninstall', true);
};
wait(200);
Expected:
firstUninstall.onsuccess: null
secondUninstall.onerror: NOT_INSTALLED
Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
spyPending(navigator.mozApps.mgmt.getAll());
Expected:
onsuccess: [
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {name: "An application which does not grant permission for any other origin to install it"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://...:...",
    receipts: null
  }
]

Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
spyPending(navigator.mozApps.install(
  SERVERS['manifest_with_bom'] + "/manifest.webapp",
  null));
Expected:
onsuccess: {...}

Got:
Error: pending is undefined

Failed example:
uninstallAll()();
Expected:
(nothing)
Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
navigator.mozApps.mgmt.addEventListener('install', installSpy);
Expected:
(nothing)
Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
navigator.mozApps.mgmt.onuninstall = uninstallSpy;
Expected:
(nothing)
Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
navigator.mozApps.mgmt.addEventListener('install', deadSpy);
Expected:
(nothing)
Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
navigator.mozApps.mgmt.removeEventListener('install', deadSpy);
Expected:
(nothing)
Got:
Error: navigator.mozApps.mgmt is undefined

Failed example:
spyPending(navigator.mozApps.install(
  SERVERS['basic_app'] + "/manifest.webapp"))
Expected:
install({
  application: {
    installOrigin: "http://?:?",
    installTime: ?,
    manifest: {installs_allowed_from: ["*"], name: "Super Crazy Basic App"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://?:?",
    receipts: null
  }
})
onsuccess: {...}
Got:
Error: pending is undefined

Failed example:
spyPending(lastPending.result.uninstall());
Expected:
uninstall({
  application: {
    installOrigin: "http://127.0.0.1:?",
    installTime: ?,
    manifest: {installs_allowed_from: ["*"], name: "Super Crazy Basic App"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://127.0.0.1:?",
    receipts: null
  }
})
onsuccess: null

Got:
Error: lastPending is null

Failed example:
var chan = embedIFrameAndStartChannel(SERVERS['no_delegated_install'] + "/include.html");
Expected:
(nothing)
Got:
Error: Channel is not defined

Failed example:
chan.call(buildJSChanArgs("install", true));
// because the spy has been called many times, we must clear its wait flag:
installSpy.calledWait = false;
installSpy.wait();
Expected:
install({
  application: {
    installOrigin: "http://127.0.0.1:?",
    installTime: ?,
    manifest: {name: "An application which does not grant permission for any other origin to install it"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://127.0.0.1:?",
    receipts: null
  }
})
success()

Got:
Error: chan is undefined

45 tests in 0 items.
7 tests of 45 passed, 38 failed.
$ // We'll show all the methods we're testing
> var arr = [];
> function iterateMethods(label, root, suppress) {
>   for (var f in root) {
>       if (suppress && suppress.indexOf(f) != -1)
>           continue;
>       if (typeof root[f] === 'function')
>           arr.push(label + f);
>   }
> }
> 
> iterateMethods("navigator.mozApps.", navigator.mozApps, ['setApplicationChooser', 'setRepoOrigin', 'setMockResponse']);
> iterateMethods("navigator.mozApps.mgmt.", navigator.mozApps.mgmt);
> 
> arr = arr.sort();
> for (var i = 0; i < arr.length; i++) writeln(arr[i]);
navigator.mozApps.getInstalled
navigator.mozApps.getSelf
navigator.mozApps.install...
navigator.mozApps.mgmt.addEventListener
navigator.mozApps.mgmt.getAll
navigator.mozApps.mgmt.removeEventListener...

Actual output:
navigator.mozApps.QueryInterface
navigator.mozApps.enumerate
navigator.mozApps.enumerateAll
navigator.mozApps.install
navigator.mozApps.launch
navigator.mozApps.uninstall
$ var lastPending = null;

$ function spyPending(pending, name, noWait) {
>   var done = false;
>   pending.onsuccess = function () {
>     done = true;
>     var desc = 'onsuccess:';
>     if (name) {
>       desc = name + '.' + desc;
>     }
>     writeln(desc, pending.result);
>   };
>   pending.onerror = function () {
>     done = true;
>     var desc = 'onerror:';
>     if (name) {
>       desc = name + '.' + desc;
>     }
>     writeln(desc, pending.error);
>   };
>   if (! noWait) {
>     wait(function () {return done;});
>   }
>   lastPending = pending;
> }

Clear All Apps

Delete all applications and then verify that getAll() yields no apps.
$ // Out of curiosity we'll see what's installed:
> spyPending(navigator.mozApps.mgmt.getAll());
onsuccess: ...
Actual output:
Error: navigator.mozApps.mgmt is undefined
$ var finished = false;

$ function uninstallAll() {
>   var pendingGetAll = navigator.mozApps.mgmt.getAll();
>   pendingGetAll.onsuccess = function() {
>     var m = this.result;
>     var total = m.length;
>     finished = (total === 0);
>     for (var i=0; i<m.length; i++) {
>       var app = m[i];
>       var pendingUninstall = app.uninstall();
>       pendingUninstall.onsuccess = function(r) {
>         finished = (--total === 0);
>       };
>       pendingUninstall.onerror = function () {
>         finished = true;
>         writeln('Error:', this.error);
>         throw('Failed');
>       };
>     }
>   };
>   return function () {
>     wait(function () {
>       if (finished) {
>         finished = false;
>         return true;
>       }
>     });
>   };
> }

$ uninstallAll()();

Actual output:
Error: navigator.mozApps.mgmt is undefined
$ spyPending(navigator.mozApps.mgmt.getAll());
onsuccess: []

Actual output:
Error: navigator.mozApps.mgmt is undefined

Install missing required arguments will throw

$ navigator.mozApps.install();
Error: install missing required url argument

Actual output:
Error: Not enough arguments [mozIDOMApplicationRegistry.install]

Install a basic application

$ navigator.mozApps.setMockResponse(true, Spy('setMockResponse', {wait: true}));
setMockResponse()
Actual output:
Error: navigator.mozApps.setMockResponse is not a function
Error: wait(called:Spy('setMockResponse')) has timed out
$ spyPending(navigator.mozApps.install(
>   SERVERS['basic_app'] + "/manifest.webapp",
>   null));
onsuccess: {
  installOrigin: "http://?:?",
  installTime: ?,
  manifest: {installs_allowed_from: ["*"], name: "Super Crazy Basic App"},
  manifestURL: "http://?:?/manifest.webapp",
  origin: "http://?:?",
  receipts: null
}
Actual output:
Error: pending is undefined
$ spyPending(navigator.mozApps.mgmt.getAll());
onsuccess: [
      {
        installOrigin: "http://?:?",
        installTime: ?,
        manifest: {installs_allowed_from: ["*"], name: "Super Crazy Basic App"},
        manifestURL: "http://?:?/manifest.webapp",
        origin: "http://?:?",
        receipts: null
      }
    ]

Actual output:
Error: navigator.mozApps.mgmt is undefined

Re-install that application with a different manifest

this should be considered an "upgrade", because we may not have two manifests per origin.
$ navigator.mozApps.setMockResponse(true, Spy('setMockResponse', {wait: true}));
setMockResponse()
Actual output:
Error: navigator.mozApps.setMockResponse is not a function
Error: wait(called:Spy('setMockResponse')) has timed out
$ spyPending(navigator.mozApps.install(
>   SERVERS['basic_app'] + "/manifest2.webapp",
>   null));
onsuccess: {...}
Actual output:
Error: pending is undefined
$ spyPending(navigator.mozApps.mgmt.getAll());
onsuccess: [
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {installs_allowed_from: ["*"], name: "Wild and Crazy Basic App"},
    manifestURL: "http://?:?/manifest2.webapp",
    origin: "http://...:...",
    receipts: null
  }
]

Actual output:
Error: navigator.mozApps.mgmt is undefined

We installed it, getInstalled should return it.

$ spyPending(navigator.mozApps.getInstalled());
onsuccess: [
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {installs_allowed_from: ["*"], name: "Wild and Crazy Basic App"},
    manifestURL: "http://?:?/manifest2.webapp",
    origin: "http://...:...",
    receipts: null
  }
]

Actual output:
Error: navigator.mozApps.getInstalled is not a function

getSelf should not.

$ spyPending(navigator.mozApps.getSelf());
onsuccess: null

Actual output:
Error: navigator.mozApps.getSelf is not a function

getSelf from basic app's domain should show the new app

Note: we're talking with the other app via JSChannel so that we can have it call getSelf instead of the test calling getSelf (which as we showed above won't return anything).

$ var chan = embedIFrameAndStartChannel(SERVERS['basic_app'] + "/include.html");
> chan.call(buildJSChanArgs("getSelf", true));
success({
  installOrigin: "http://...:...",
  installTime: ...,
  manifest: {installs_allowed_from: ["*"], name: "Wild and Crazy Basic App"},
  manifestURL: "http://?:?/manifest2.webapp",
  origin: "http://...:...",
  receipts: null
})

Actual output:
Error: Channel is not defined

Installation of an app with a syntax error in manifest

$ spyPending(navigator.mozApps.install(
>   SERVERS['json_syntax_error'] + "/manifest.webapp",
>   null));
onerror: MANIFEST_PARSE_ERROR

Actual output:
Error: pending is undefined

Installation of an app with a malformed manifest (missing key)

$ spyPending(navigator.mozApps.install(
>   SERVERS['missing_required_field'] + "/manifest.webapp",
>   null));
onerror: INVALID_MANIFEST

Actual output:
Error: pending is undefined

Installation of an app without required HTTP Content-Type

$ spyPending(navigator.mozApps.install(
>   SERVERS['bad_content_type'] + "/manifest.json",
>   null));
onerror: INVALID_MANIFEST

Actual output:
Error: pending is undefined

Installation of an app without delegated installation permissions

$ spyPending(navigator.mozApps.install(
>   SERVERS['no_delegated_install'] + "/manifest.webapp",
>   null));
onerror: PERMISSION_DENIED

Actual output:
Error: pending is undefined

Installation of that same app, from its own origin

NOTE: This is a rather tricky test: We'll programatically embed an iframe from a non-repo origin and load web content from that origin. The content (no_mgmt_api_off_repo_origin/include.html) uses jschannel to allow us to programmatically drive it running queries against the test app repo from off domain.

$ var chan = embedIFrameAndStartChannel(SERVERS['no_delegated_install'] + "/include.html");

Actual output:
Error: Channel is not defined
$ chan.call(buildJSChanArgs("install", true));
success()
Actual output:
Error: chan is undefined
$ // now getInstalled should show that we're installed
> chan.call(buildJSChanArgs("getSelf", true));
success({
  installOrigin: "http://...:...",
  installTime: ...,
  manifest: {name: "An application which does not grant permission for any other origin to install it"},
  manifestURL: "http://?:?/manifest.webapp",
  origin: "http://...:...",
  receipts: null
})
Actual output:
Error: chan is undefined
$ // and getInstalledBy should show that same result
> chan.call(buildJSChanArgs("getInstalled", true));
success([
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {name: "An application which does not grant permission for any other origin to install it"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://...:...",
    receipts: null
  }
])

Actual output:
Error: chan is undefined

getInstalled from origin shouldn't show second app

$ spyPending(navigator.mozApps.getInstalled());
onsuccess: [
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {installs_allowed_from: ["*"], name: "Wild and Crazy Basic App"},
    manifestURL: "http://?:?/manifest2.webapp",
    origin: "http://...:...",
    receipts: null
  }
]

Actual output:
Error: navigator.mozApps.getInstalled is not a function

getAll should now contain two apps

$ var spy = Spy('list');
> var pendingGetAll = navigator.mozApps.mgmt.getAll();
> pendingGetAll.onsuccess = function() {
>   for (var i=0; i<this.result.length; i++) {
>     writeln('Origin: ', this.result[i].origin);
>   }
>   spy.func(i);
>  };
> spy.wait();
Origin: ...
Origin: ...
list(2)

Actual output:
Error: navigator.mozApps.mgmt is undefined

Verify mgmt.getAll don't work off repo origin

$ // first let's add an iframe with the child to the document */
> var chan = embedIFrameAndStartChannel(SERVERS['no_mgmt_api_off_repo_origin'] + "/include.html");

Actual output:
Error: Channel is not defined
$ // Note the exact error here is not so clear, so we kind of punt:
> chan.call(buildJSChanArgs("getAll", false));
error("...")

Actual output:
Error: chan is undefined

Verify no callbacks are required to uninstall()

All args are optional to uninstall. To test this we'll uninstall one app, wait 200ms, and then verify that list returns a single app.

$ var pendingGetAll1 = navigator.mozApps.mgmt.getAll();
> pendingGetAll1.onsuccess = function() {
>   spyPending(this.result[0].uninstall(), 'firstUninstall', true);
>   spyPending(this.result[0].uninstall(), 'secondUninstall', true);
> };
> wait(200);
firstUninstall.onsuccess: null
secondUninstall.onerror: NOT_INSTALLED
Actual output:
Error: navigator.mozApps.mgmt is undefined
$ spyPending(navigator.mozApps.mgmt.getAll());
onsuccess: [
  {
    installOrigin: "http://...:...",
    installTime: ...,
    manifest: {name: "An application which does not grant permission for any other origin to install it"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://...:...",
    receipts: null
  }
]

Actual output:
Error: navigator.mozApps.mgmt is undefined

Install an app with a UTF-8 BOM in the manifest

$ spyPending(navigator.mozApps.install(
>   SERVERS['manifest_with_bom'] + "/manifest.webapp",
>   null));
onsuccess: {...}

Actual output:
Error: pending is undefined

Events

First we'll just test that adding and removing watchers works

$ uninstallAll()();

Actual output:
Error: navigator.mozApps.mgmt is undefined
$ installSpy = Spy('install');

$ uninstallSpy = Spy('uninstall');

$ navigator.mozApps.mgmt.addEventListener('install', installSpy);

Actual output:
Error: navigator.mozApps.mgmt is undefined
$ navigator.mozApps.mgmt.onuninstall = uninstallSpy;

Actual output:
Error: navigator.mozApps.mgmt is undefined
$ deadSpy = Spy('should_not_fire');

$ navigator.mozApps.mgmt.addEventListener('install', deadSpy);

Actual output:
Error: navigator.mozApps.mgmt is undefined
$ navigator.mozApps.mgmt.removeEventListener('install', deadSpy);

Actual output:
Error: navigator.mozApps.mgmt is undefined

Next we'll install and remove apps to get the events:

$ spyPending(navigator.mozApps.install(
>   SERVERS['basic_app'] + "/manifest.webapp"))
install({
  application: {
    installOrigin: "http://?:?",
    installTime: ?,
    manifest: {installs_allowed_from: ["*"], name: "Super Crazy Basic App"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://?:?",
    receipts: null
  }
})
onsuccess: {...}
Actual output:
Error: pending is undefined
$ spyPending(lastPending.result.uninstall());
uninstall({
  application: {
    installOrigin: "http://127.0.0.1:?",
    installTime: ?,
    manifest: {installs_allowed_from: ["*"], name: "Super Crazy Basic App"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://127.0.0.1:?",
    receipts: null
  }
})
onsuccess: null

Actual output:
Error: lastPending is null

Now we'll install an app in an iframe, and check that we detect the change in this page:

$ var chan = embedIFrameAndStartChannel(SERVERS['no_delegated_install'] + "/include.html");

Actual output:
Error: Channel is not defined
$ chan.call(buildJSChanArgs("install", true));
> // because the spy has been called many times, we must clear its wait flag:
> installSpy.calledWait = false;
> installSpy.wait();
install({
  application: {
    installOrigin: "http://127.0.0.1:?",
    installTime: ?,
    manifest: {name: "An application which does not grant permission for any other origin to install it"},
    manifestURL: "http://?:?/manifest.webapp",
    origin: "http://127.0.0.1:?",
    receipts: null
  }
})
success()

Actual output:
Error: chan is undefined