test-system-events.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. const events = require("sdk/system/events");
  5. const self = require("sdk/self");
  6. const { Cc, Ci, Cu } = require("chrome");
  7. const { setTimeout } = require("sdk/timers");
  8. const { Loader, LoaderWithHookedConsole2 } = require("sdk/test/loader");
  9. const nsIObserverService = Cc["@mozilla.org/observer-service;1"].
  10. getService(Ci.nsIObserverService);
  11. let isConsoleEvent = (topic) =>
  12. !!~["console-api-log-event", "console-storage-cache-event"].indexOf(topic)
  13. exports["test basic"] = function(assert) {
  14. let type = Date.now().toString(32);
  15. let timesCalled = 0;
  16. function handler({subject, data}) { timesCalled++; };
  17. events.on(type, handler);
  18. events.emit(type, { data: "yo yo" });
  19. assert.equal(timesCalled, 1, "event handler was called");
  20. events.off(type, handler);
  21. events.emit(type, { data: "no way" });
  22. assert.equal(timesCalled, 1, "removed handler is no longer called");
  23. events.once(type, handler);
  24. events.emit(type, { data: "and we meet again" });
  25. events.emit(type, { data: "it's always hard to say bye" });
  26. assert.equal(timesCalled, 2, "handlers added via once are triggered once");
  27. }
  28. exports["test simple argument passing"] = function (assert) {
  29. let type = Date.now().toString(32);
  30. let lastArg;
  31. function handler({data}) { lastArg = data; }
  32. events.on(type, handler);
  33. [true, false, 100, 0, 'a string', ''].forEach(arg => {
  34. events.emit(type, arg);
  35. assert.strictEqual(lastArg, arg + '',
  36. 'event emitted for ' + arg + ' has correct data value');
  37. events.emit(type, { data: arg });
  38. assert.strictEqual(lastArg, arg + '',
  39. 'event emitted for ' + arg + ' has correct data value when a property on an object');
  40. });
  41. [null, undefined, {}].forEach(arg => {
  42. events.emit(type, arg);
  43. assert.strictEqual(lastArg, null,
  44. 'emitting ' + arg + ' gets null data');
  45. });
  46. events.off(type, handler);
  47. };
  48. exports["test error reporting"] = function(assert) {
  49. let { loader, messages } = LoaderWithHookedConsole2(module);
  50. let events = loader.require("sdk/system/events");
  51. function brokenHandler(subject, data) { throw new Error("foo"); };
  52. let lineNumber;
  53. try { brokenHandler() } catch (error) { lineNumber = error.lineNumber }
  54. let errorType = Date.now().toString(32);
  55. events.on(errorType, brokenHandler);
  56. events.emit(errorType, { data: "yo yo" });
  57. assert.equal(messages.length, 2, "Got an exception");
  58. assert.equal(messages[0], "console.error: " + self.name + ": \n",
  59. "error is logged");
  60. let text = messages[1];
  61. assert.ok(text.indexOf("Error: foo") >= 0, "error message is logged");
  62. assert.ok(text.indexOf(module.uri) >= 0, "module uri is logged");
  63. assert.ok(text.indexOf(lineNumber) >= 0, "error line is logged");
  64. events.off(errorType, brokenHandler);
  65. loader.unload();
  66. };
  67. exports["test listeners are GC-ed"] = function(assert, done) {
  68. let receivedFromWeak = [];
  69. let receivedFromStrong = [];
  70. let loader = Loader(module);
  71. let events = loader.require('sdk/system/events');
  72. let type = 'test-listeners-are-garbage-collected';
  73. function handler(event) { receivedFromStrong.push(event); }
  74. function weakHandler(event) { receivedFromWeak.push(event); }
  75. events.on(type, handler, true);
  76. events.on(type, weakHandler);
  77. events.emit(type, { data: 1 });
  78. assert.equal(receivedFromStrong.length, 1, "strong listener invoked");
  79. assert.equal(receivedFromWeak.length, 1, "weak listener invoked");
  80. handler = weakHandler = null;
  81. Cu.schedulePreciseGC(function() {
  82. events.emit(type, { data: 2 });
  83. assert.equal(receivedFromWeak.length, 1, "weak listener was GC-ed");
  84. assert.equal(receivedFromStrong.length, 2, "strong listener was invoked");
  85. loader.unload();
  86. done();
  87. });
  88. };
  89. exports["test handle nsIObserverService notifications"] = function(assert) {
  90. let ios = Cc['@mozilla.org/network/io-service;1']
  91. .getService(Ci.nsIIOService);
  92. let uri = ios.newURI("http://www.foo.com", null, null);
  93. let type = Date.now().toString(32);
  94. let timesCalled = 0;
  95. let lastSubject = null;
  96. let lastData = null;
  97. let lastType = null;
  98. function handler({ subject, data, type }) {
  99. // Ignores internal console events
  100. if (isConsoleEvent(type))
  101. return;
  102. timesCalled++;
  103. lastSubject = subject;
  104. lastData = data;
  105. lastType = type;
  106. };
  107. events.on(type, handler);
  108. nsIObserverService.notifyObservers(uri, type, "some data");
  109. assert.equal(timesCalled, 1, "notification invokes handler");
  110. assert.equal(lastType, type, "event.type is notification topic");
  111. assert.equal(lastSubject, uri, "event.subject is notification subject");
  112. assert.equal(lastData, "some data", "event.data is notification data");
  113. function customSubject() {}
  114. function customData() {}
  115. events.emit(type, { data: customData, subject: customSubject });
  116. assert.equal(timesCalled, 2, "notification invokes handler");
  117. assert.equal(lastType, type, "event.type is notification topic");
  118. assert.equal(lastSubject, customSubject,
  119. "event.subject is wrapped & unwrapped");
  120. assert.equal(lastData, customData, "event.data is wrapped & unwrapped");
  121. events.off(type, handler);
  122. nsIObserverService.notifyObservers(null, type, "some data");
  123. assert.equal(timesCalled, 2, "event handler is removed");
  124. events.on("*", handler);
  125. nsIObserverService.notifyObservers(null, type, "more data");
  126. assert.equal(timesCalled, 3, "notification invokes * handler");
  127. assert.equal(lastType, type, "event.type is notification topic");
  128. assert.equal(lastSubject, null,
  129. "event.subject is notification subject");
  130. assert.equal(lastData, "more data", "event.data is notification data");
  131. events.off("*", handler);
  132. nsIObserverService.notifyObservers(null, type, "last data");
  133. assert.equal(timesCalled, 3, "* event handler is removed");
  134. };
  135. exports["test emit to nsIObserverService observers"] = function(assert) {
  136. let ios = Cc['@mozilla.org/network/io-service;1']
  137. .getService(Ci.nsIIOService);
  138. let uri = ios.newURI("http://www.foo.com", null, null);
  139. let timesCalled = 0;
  140. let lastSubject = null;
  141. let lastData = null;
  142. let lastTopic = null;
  143. var topic = Date.now().toString(32)
  144. let nsIObserver = {
  145. QueryInterface: function() {
  146. return nsIObserver;
  147. },
  148. observe: function(subject, topic, data) {
  149. // Ignores internal console events
  150. if (isConsoleEvent(topic))
  151. return;
  152. timesCalled = timesCalled + 1;
  153. lastSubject = subject;
  154. lastData = data;
  155. lastTopic = topic;
  156. }
  157. };
  158. nsIObserverService.addObserver(nsIObserver, topic, false);
  159. events.emit(topic, { subject: uri, data: "some data" });
  160. assert.equal(timesCalled, 1, "emit notifies observers");
  161. assert.equal(lastTopic, topic, "event type is notification topic");
  162. assert.equal(lastSubject.wrappedJSObject.object, uri,
  163. "event.subject is notification subject");
  164. assert.equal(lastData, "some data", "event.data is notification data");
  165. function customSubject() {}
  166. function customData() {}
  167. events.emit(topic, { subject: customSubject, data: customData });
  168. assert.equal(timesCalled, 2, "emit notifies observers");
  169. assert.equal(lastTopic, topic, "event.type is notification");
  170. assert.equal(lastSubject.wrappedJSObject.object, customSubject,
  171. "event.subject is notification subject");
  172. assert.equal(lastData, customData, "event.data is notification data");
  173. nsIObserverService.removeObserver(nsIObserver, topic);
  174. events.emit(topic, { data: "more data" });
  175. assert.equal(timesCalled, 2, "removed observers no longer invoked");
  176. nsIObserverService.addObserver(nsIObserver, "*", false);
  177. events.emit(topic, { data: "data again" });
  178. assert.equal(timesCalled, 3, "emit notifies * observers");
  179. assert.equal(lastTopic, topic, "event.type is notification");
  180. assert.equal(lastSubject, null,
  181. "event.subject is notification subject");
  182. assert.equal(lastData, "data again", "event.data is notification data");
  183. nsIObserverService.removeObserver(nsIObserver, "*");
  184. events.emit(topic, { data: "last data" });
  185. assert.equal(timesCalled, 3, "removed observers no longer invoked");
  186. }
  187. require("test").run(exports);