PageRenderTime 57ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/test_Signal.js

https://github.com/ccnmtl/mochikit-mirror
JavaScript | 540 lines | 437 code | 91 blank | 12 comment | 19 complexity | a538536e105a7fd2705acee350539b93 MD5 | raw file
  1. if (typeof(tests) == 'undefined') { tests = {}; }
  2. tests.test_Signal = function (t) {
  3. var submit = MochiKit.DOM.getElement('submit');
  4. var ident = null;
  5. var i = 0;
  6. var aFunction = function() {
  7. t.ok(this === submit, "aFunction should have 'this' as submit");
  8. i++;
  9. if (typeof(this.someVar) != 'undefined') {
  10. i += this.someVar;
  11. }
  12. };
  13. var bFunction = function(someArg, someOtherArg) {
  14. if (typeof(someArg) == "number") {
  15. i += someArg;
  16. }
  17. if (typeof(someOtherArg) == "number") {
  18. i += someOtherArg;
  19. }
  20. };
  21. var aObject = {};
  22. aObject.aMethod = function() {
  23. t.ok(this === aObject, "aMethod should have 'this' as aObject");
  24. i++;
  25. };
  26. ident = connect('submit', 'onclick', aFunction);
  27. MochiKit.DOM.getElement('submit').click();
  28. t.is(i, 1, 'HTML onclick event can be connected to a function');
  29. disconnect(ident);
  30. MochiKit.DOM.getElement('submit').click();
  31. t.is(i, 1, 'HTML onclick can be disconnected from a function');
  32. var submit = MochiKit.DOM.getElement('submit');
  33. ident = connect(submit, 'onclick', aFunction);
  34. submit.click();
  35. t.is(i, 2, 'Checking that a DOM element can be connected to a function');
  36. disconnect(ident);
  37. submit.click();
  38. t.is(i, 2, '...and then disconnected');
  39. ident = connect(submit, 'onclick', aObject, 'aMethod');
  40. submit.click();
  41. t.is(i, 3, 'Checking that a DOM element can be connected to a method');
  42. disconnect(ident);
  43. submit.click();
  44. t.is(i, 3, '...and disconnected again');
  45. if (MochiKit.DOM.getElement('submit').fireEvent ||
  46. (document.createEvent &&
  47. typeof(document.createEvent('MouseEvents').initMouseEvent) == 'function')) {
  48. /*
  49. Adapted from:
  50. http://www.devdaily.com/java/jwarehouse/jforum/tests/selenium/javascript/htmlutils.js.shtml
  51. License: Apache
  52. Copyright: Copyright 2004 ThoughtWorks, Inc
  53. */
  54. var triggerMouseEvent = function(element, eventType, canBubble) {
  55. var element = MochiKit.DOM.getElement(element);
  56. var canBubble = (typeof(canBubble) == 'undefined') ? true : canBubble;
  57. if (element.fireEvent) {
  58. var newEvt = document.createEventObject();
  59. newEvt.clientX = 1;
  60. newEvt.clientY = 1;
  61. newEvt.button = 1;
  62. newEvt.detail = 3;
  63. element.fireEvent('on' + eventType, newEvt);
  64. } else if (document.createEvent && (typeof(document.createEvent('MouseEvents').initMouseEvent) == 'function')) {
  65. var evt = document.createEvent('MouseEvents');
  66. evt.initMouseEvent(eventType, canBubble, true, // event, bubbles, cancelable
  67. document.defaultView, 3, // view, detail (either scroll or # of clicks)
  68. 1, 0, 0, 0, // screenX, screenY, clientX, clientY
  69. false, false, false, false, // ctrlKey, altKey, shiftKey, metaKey
  70. 0, null); // buttonCode, relatedTarget
  71. element.dispatchEvent(evt);
  72. }
  73. };
  74. var eventTest = function(e) {
  75. i++;
  76. t.ok((typeof(e.event()) === 'object'), 'checking that event() is an object');
  77. t.ok((typeof(e.type()) === 'string'), 'checking that type() is a string');
  78. t.ok((e.target() === MochiKit.DOM.getElement('submit')), 'checking that target is "submit"');
  79. t.ok((typeof(e.modifier()) === 'object'), 'checking that modifier() is an object');
  80. t.ok(e.modifier().alt === false, 'checking that modifier().alt is defined, but false');
  81. t.ok(e.modifier().ctrl === false, 'checking that modifier().ctrl is defined, but false');
  82. t.ok(e.modifier().meta === false, 'checking that modifier().meta is defined, but false');
  83. t.ok(e.modifier().shift === false, 'checking that modifier().shift is defined, but false');
  84. t.ok((typeof(e.mouse()) === 'object'), 'checking that mouse() is an object');
  85. t.ok((typeof(e.mouse().button) === 'object'), 'checking that mouse().button is an object');
  86. t.ok(e.mouse().button.left === true, 'checking that mouse().button.left is true');
  87. t.ok(e.mouse().button.middle === false, 'checking that mouse().button.middle is false');
  88. t.ok(e.mouse().button.right === false, 'checking that mouse().button.right is false');
  89. t.ok((typeof(e.mouse().page) === 'object'), 'checking that mouse().page is an object');
  90. t.ok((typeof(e.mouse().page.x) === 'number'), 'checking that mouse().page.x is a number');
  91. t.ok((typeof(e.mouse().page.y) === 'number'), 'checking that mouse().page.y is a number');
  92. t.ok((typeof(e.mouse().client) === 'object'), 'checking that mouse().client is an object');
  93. t.ok((typeof(e.mouse().client.x) === 'number'), 'checking that mouse().client.x is a number');
  94. t.ok((typeof(e.mouse().client.y) === 'number'), 'checking that mouse().client.y is a number');
  95. /* these should not be defined */
  96. t.ok((typeof(e.relatedTarget()) === 'undefined'), 'checking that relatedTarget() is undefined');
  97. t.ok((typeof(e.key()) === 'undefined'), 'checking that key() is undefined');
  98. t.ok((typeof(e.mouse().wheel) === 'undefined'), 'checking that mouse().wheel is undefined');
  99. };
  100. ident = connect('submit', 'onmousedown', eventTest);
  101. triggerMouseEvent('submit', 'mousedown', false);
  102. t.is(i, 4, 'Connecting an event to an HTML object and firing a synthetic event');
  103. disconnect(ident);
  104. triggerMouseEvent('submit', 'mousedown', false);
  105. t.is(i, 4, 'Disconnecting an event to an HTML object and firing a synthetic event');
  106. ident = connect('submit', 'onmousewheel', function(e) {
  107. i++;
  108. t.ok((typeof(e.mouse()) === 'object'), 'checking that mouse() is an object');
  109. t.ok((typeof(e.mouse().wheel) === 'object'), 'checking that mouse().wheel is an object');
  110. t.ok((typeof(e.mouse().wheel.x) === 'number'), 'checking that mouse().wheel.x is a number');
  111. t.ok((typeof(e.mouse().wheel.y) === 'number'), 'checking that mouse().wheel.y is a number');
  112. });
  113. var nativeSignal = 'mousewheel';
  114. if (MochiKit.Signal._browserLacksMouseWheelEvent()) {
  115. nativeSignal = 'DOMMouseScroll';
  116. }
  117. triggerMouseEvent('submit', nativeSignal, false);
  118. t.is(i, 5, 'Connecting a mousewheel event to an HTML object and firing a synthetic event');
  119. disconnect(ident);
  120. triggerMouseEvent('submit', nativeSignal, false);
  121. t.is(i, 5, 'Disconnecting a mousewheel event to an HTML object and firing a synthetic event');
  122. }
  123. // non-event signals to DOM nodes
  124. i = 0;
  125. ident = connect(submit, 'onclick', bFunction);
  126. signal(submit, 'onclick', 1, 2);
  127. t.is(i, 3, 'Manual signal() from DOM element to a function');
  128. disconnect(ident);
  129. signal(submit, 'onclick', 1, 2);
  130. t.is(i, 3, '...and disconnected signals are not called');
  131. i = 0;
  132. ident = connect(submit, 'ontest', bFunction);
  133. signal(submit, 'ontest', 1, 2);
  134. t.is(i, 3, 'Manual signal() from DOM element with custom signal name');
  135. disconnect(ident);
  136. signal(submit, 'ontest', 1, 2);
  137. t.is(i, 3, '...and disconnected signals are not called');
  138. i = 0;
  139. ident = connect(submit, 'onclick', aObject, 'aMethod');
  140. signal(submit, 'onclick', 1, 2);
  141. t.is(i, 1, 'Manual signal() from DOM element to a method');
  142. disconnect(ident);
  143. signal(submit, 'onclick', 1, 2);
  144. t.is(i, 1, '...and disconnected signals are not called');
  145. // non-DOM tests
  146. var hasNoSignals = {};
  147. var hasSignals = {someVar: 1};
  148. var i = 0;
  149. var aFunction = function() {
  150. i++;
  151. if (typeof(this.someVar) != 'undefined') {
  152. i += this.someVar;
  153. }
  154. };
  155. var bFunction = function(someArg, someOtherArg) {
  156. i += someArg + someOtherArg;
  157. };
  158. var aObject = {};
  159. aObject.aMethod = function() {
  160. i++;
  161. };
  162. aObject.bMethod = function() {
  163. i++;
  164. };
  165. var bObject = {};
  166. bObject.bMethod = function() {
  167. i++;
  168. };
  169. ident = connect(hasSignals, 'signalOne', aFunction);
  170. signal(hasSignals, 'signalOne');
  171. t.is(i, 2, 'Connecting function');
  172. i = 0;
  173. disconnect(ident);
  174. signal(hasSignals, 'signalOne');
  175. t.is(i, 0, 'New style disconnecting function');
  176. i = 0;
  177. ident = connect(hasSignals, 'signalOne', bFunction);
  178. signal(hasSignals, 'signalOne', 1, 2);
  179. t.is(i, 3, 'Connecting function');
  180. i = 0;
  181. disconnect(ident);
  182. signal(hasSignals, 'signalOne', 1, 2);
  183. t.is(i, 0, 'New style disconnecting function');
  184. i = 0;
  185. connect(hasSignals, 'signalOne', aFunction);
  186. signal(hasSignals, 'signalOne');
  187. t.is(i, 2, 'Connecting function');
  188. i = 0;
  189. disconnect(hasSignals, 'signalOne', aFunction);
  190. signal(hasSignals, 'signalOne');
  191. t.is(i, 0, 'Old style disconnecting function');
  192. i = 0;
  193. ident = connect(hasSignals, 'signalOne', aObject, aObject.aMethod);
  194. signal(hasSignals, 'signalOne');
  195. t.is(i, 1, 'Connecting obj-function');
  196. i = 0;
  197. disconnect(ident);
  198. signal(hasSignals, 'signalOne');
  199. t.is(i, 0, 'New style disconnecting obj-function');
  200. i = 0;
  201. connect(hasSignals, 'signalOne', aObject, aObject.aMethod);
  202. signal(hasSignals, 'signalOne');
  203. t.is(i, 1, 'Connecting obj-function');
  204. i = 0;
  205. disconnect(hasSignals, 'signalOne', aObject, aObject.aMethod);
  206. signal(hasSignals, 'signalOne');
  207. t.is(i, 0, 'Disconnecting obj-function');
  208. i = 0;
  209. ident = connect(hasSignals, 'signalTwo', aObject, 'aMethod');
  210. signal(hasSignals, 'signalTwo');
  211. t.is(i, 1, 'Connecting obj-string');
  212. i = 0;
  213. disconnect(ident);
  214. signal(hasSignals, 'signalTwo');
  215. t.is(i, 0, 'New style disconnecting obj-string');
  216. i = 0;
  217. connect(hasSignals, 'signalTwo', aObject, 'aMethod');
  218. signal(hasSignals, 'signalTwo');
  219. t.is(i, 1, 'Connecting obj-string');
  220. i = 0;
  221. disconnect(hasSignals, 'signalTwo', aObject, 'aMethod');
  222. signal(hasSignals, 'signalTwo');
  223. t.is(i, 0, 'Old style disconnecting obj-string');
  224. i = 0;
  225. var shouldRaise = function() { return undefined.attr; };
  226. try {
  227. connect(hasSignals, 'signalOne', shouldRaise);
  228. ident = connect(hasSignals, 'signalOne', aFunction);
  229. signal(hasSignals, 'signalOne');
  230. t.ok(false, 'An exception was not raised');
  231. } catch (e) {
  232. t.ok(true, 'An exception was raised');
  233. }
  234. disconnect(hasSignals, 'signalOne', shouldRaise);
  235. disconnect(ident);
  236. t.is(i, 2, 'Exception raised, but signal was sent to all listeners');
  237. i = 0;
  238. connect(hasSignals, 'signalOne', aObject, 'aMethod');
  239. connect(hasSignals, 'signalOne', aObject, 'bMethod');
  240. signal(hasSignals, 'signalOne');
  241. t.is(i, 2, 'Connecting one signal to two slots in one object');
  242. i = 0;
  243. disconnect(hasSignals, 'signalOne', aObject, 'aMethod');
  244. disconnect(hasSignals, 'signalOne', aObject, 'bMethod');
  245. signal(hasSignals, 'signalOne');
  246. t.is(i, 0, 'Disconnecting one signal from two slots in one object');
  247. i = 0;
  248. connect(hasSignals, 'signalOne', aObject, 'aMethod');
  249. connect(hasSignals, 'signalOne', bObject, 'bMethod');
  250. signal(hasSignals, 'signalOne');
  251. t.is(i, 2, 'Connecting one signal to two slots in two objects');
  252. i = 0;
  253. disconnect(hasSignals, 'signalOne', aObject, 'aMethod');
  254. disconnect(hasSignals, 'signalOne', bObject, 'bMethod');
  255. signal(hasSignals, 'signalOne');
  256. t.is(i, 0, 'Disconnecting one signal from two slots in two objects');
  257. i = 0;
  258. try {
  259. connect(nothing, 'signalOne', aObject, 'aMethod');
  260. signal(nothing, 'signalOne');
  261. t.ok(false, 'An exception was not raised when connecting undefined');
  262. } catch (e) {
  263. t.ok(true, 'An exception was raised when connecting undefined');
  264. }
  265. try {
  266. disconnect(nothing, 'signalOne', aObject, 'aMethod');
  267. t.ok(false, 'An exception was not raised when disconnecting undefined');
  268. } catch (e) {
  269. t.ok(true, 'An exception was raised when disconnecting undefined');
  270. }
  271. try {
  272. connect(hasSignals, 'signalOne', nothing);
  273. signal(hasSignals, 'signalOne');
  274. t.ok(false, 'An exception was not raised when connecting an undefined function');
  275. } catch (e) {
  276. t.ok(true, 'An exception was raised when connecting an undefined function');
  277. }
  278. try {
  279. disconnect(hasSignals, 'signalOne', nothing);
  280. t.ok(false, 'An exception was not raised when disconnecting an undefined function');
  281. } catch (e) {
  282. t.ok(true, 'An exception was raised when disconnecting an undefined function');
  283. }
  284. try {
  285. connect(hasSignals, 'signalOne', aObject, aObject.nothing);
  286. signal(hasSignals, 'signalOne');
  287. t.ok(false, 'An exception was not raised when connecting an undefined method');
  288. } catch (e) {
  289. t.ok(true, 'An exception was raised when connecting an undefined method');
  290. }
  291. try {
  292. connect(hasSignals, 'signalOne', aObject, 'nothing');
  293. signal(hasSignals, 'signalOne');
  294. t.ok(false, 'An exception was not raised when connecting an undefined method (as string)');
  295. } catch (e) {
  296. t.ok(true, 'An exception was raised when connecting an undefined method (as string)');
  297. }
  298. t.is(i, 0, 'Signals should not have fired');
  299. connect(hasSignals, 'signalOne', aFunction);
  300. connect(hasSignals, 'signalOne', aObject, 'aMethod');
  301. disconnectAll(hasSignals, 'signalOne');
  302. signal(hasSignals, 'signalOne');
  303. t.is(i, 0, 'disconnectAll works with single explicit signal');
  304. i = 0;
  305. connect(hasSignals, 'signalOne', aFunction);
  306. connect(hasSignals, 'signalOne', aObject, 'aMethod');
  307. connect(hasSignals, 'signalTwo', aFunction);
  308. connect(hasSignals, 'signalTwo', aObject, 'aMethod');
  309. disconnectAll(hasSignals, 'signalOne');
  310. signal(hasSignals, 'signalOne');
  311. t.is(i, 0, 'disconnectAll works with single explicit signal');
  312. signal(hasSignals, 'signalTwo');
  313. t.is(i, 3, 'disconnectAll does not disconnect unrelated signals');
  314. i = 0;
  315. connect(hasSignals, 'signalOne', aFunction);
  316. connect(hasSignals, 'signalOne', aObject, 'aMethod');
  317. connect(hasSignals, 'signalTwo', aFunction);
  318. connect(hasSignals, 'signalTwo', aObject, 'aMethod');
  319. disconnectAll(hasSignals, 'signalOne', 'signalTwo');
  320. signal(hasSignals, 'signalOne');
  321. signal(hasSignals, 'signalTwo');
  322. t.is(i, 0, 'disconnectAll works with two explicit signals');
  323. i = 0;
  324. connect(hasSignals, 'signalOne', aFunction);
  325. connect(hasSignals, 'signalOne', aObject, 'aMethod');
  326. connect(hasSignals, 'signalTwo', aFunction);
  327. connect(hasSignals, 'signalTwo', aObject, 'aMethod');
  328. disconnectAll(hasSignals, ['signalOne', 'signalTwo']);
  329. signal(hasSignals, 'signalOne');
  330. signal(hasSignals, 'signalTwo');
  331. t.is(i, 0, 'disconnectAll works with two explicit signals as a list');
  332. i = 0;
  333. connect(hasSignals, 'signalOne', aFunction);
  334. connect(hasSignals, 'signalOne', aObject, 'aMethod');
  335. connect(hasSignals, 'signalTwo', aFunction);
  336. connect(hasSignals, 'signalTwo', aObject, 'aMethod');
  337. disconnectAll(hasSignals);
  338. signal(hasSignals, 'signalOne');
  339. signal(hasSignals, 'signalTwo');
  340. t.is(i, 0, 'disconnectAll works with implicit signals');
  341. i = 0;
  342. var toggle = function() {
  343. disconnectAll(hasSignals, 'signalOne');
  344. connect(hasSignals, 'signalOne', aFunction);
  345. i++;
  346. };
  347. connect(hasSignals, 'signalOne', aFunction);
  348. connect(hasSignals, 'signalTwo', function() { i++; });
  349. connect(hasSignals, 'signalTwo', toggle);
  350. connect(hasSignals, 'signalTwo', function() { i++; }); // #147
  351. connect(hasSignals, 'signalTwo', function() { i++; });
  352. signal(hasSignals, 'signalTwo');
  353. t.is(i, 4, 'disconnectAll fired in a signal loop works');
  354. i = 0;
  355. disconnectAll(hasSignals, 'signalOne', 'signalTwo');
  356. // Test reentrant signals (#346)
  357. var toggle = function() {
  358. disconnectAll(hasSignals, 'signalTwo');
  359. signal(hasSignals, 'signalTwo');
  360. };
  361. connect(hasSignals, 'signalTwo', function() { i++; });
  362. connect(hasSignals, 'signalOne', toggle);
  363. connect(hasSignals, 'signalOne', function() { i++; });
  364. connect(hasSignals, 'signalOne', function() { i++; });
  365. signal(hasSignals, 'signalOne');
  366. t.is(i, 2, 'disconnectAll & signal fired in an observer works');
  367. i = 0;
  368. disconnectAll(hasSignals, 'signalOne', 'signalTwo');
  369. var testfunc = function () { arguments.callee.count++; };
  370. testfunc.count = 0;
  371. var testObj = {
  372. methOne: function () { this.countOne++; }, countOne: 0,
  373. methTwo: function () { this.countTwo++; }, countTwo: 0
  374. };
  375. connect(hasSignals, 'signalOne', testfunc);
  376. connect(hasSignals, 'signalTwo', testfunc);
  377. signal(hasSignals, 'signalOne');
  378. signal(hasSignals, 'signalTwo');
  379. t.is(testfunc.count, 2, 'disconnectAllTo func precondition');
  380. disconnectAllTo(testfunc);
  381. signal(hasSignals, 'signalOne');
  382. signal(hasSignals, 'signalTwo');
  383. t.is(testfunc.count, 2, 'disconnectAllTo func');
  384. connect(hasSignals, 'signalOne', testObj, 'methOne');
  385. connect(hasSignals, 'signalTwo', testObj, 'methTwo');
  386. signal(hasSignals, 'signalOne');
  387. signal(hasSignals, 'signalTwo');
  388. t.is(testObj.countOne, 1, 'disconnectAllTo obj precondition');
  389. t.is(testObj.countTwo, 1, 'disconnectAllTo obj precondition');
  390. disconnectAllTo(testObj);
  391. signal(hasSignals, 'signalOne');
  392. signal(hasSignals, 'signalTwo');
  393. t.is(testObj.countOne, 1, 'disconnectAllTo obj');
  394. t.is(testObj.countTwo, 1, 'disconnectAllTo obj');
  395. testObj.countOne = testObj.countTwo = 0;
  396. connect(hasSignals, 'signalOne', testObj, 'methOne');
  397. connect(hasSignals, 'signalTwo', testObj, 'methTwo');
  398. disconnectAllTo(testObj, 'methOne');
  399. signal(hasSignals, 'signalOne');
  400. signal(hasSignals, 'signalTwo');
  401. t.is(testObj.countOne, 0, 'disconnectAllTo obj+str');
  402. t.is(testObj.countTwo, 1, 'disconnectAllTo obj+str');
  403. var has__Connect = {
  404. count: 0,
  405. __connect__: function (ident) {
  406. this.count += arguments.length;
  407. disconnect(ident);
  408. }
  409. };
  410. connect(has__Connect, 'signalOne', function() {
  411. t.fail("__connect__ should have disconnected signal");
  412. });
  413. t.is(has__Connect.count, 3, '__connect__ is called when it exists');
  414. signal(has__Connect, 'signalOne');
  415. var has__Disconnect = {
  416. count: 0,
  417. __disconnect__: function (ident) {
  418. this.count += arguments.length;
  419. }
  420. };
  421. connect(has__Disconnect, 'signalOne', aFunction);
  422. connect(has__Disconnect, 'signalTwo', aFunction);
  423. disconnectAll(has__Disconnect);
  424. t.is(has__Disconnect.count, 8, '__disconnect__ is called when it exists');
  425. var events = {};
  426. var test_ident = connect(events, "test", function() {
  427. var fail_ident = connect(events, "fail", function () {
  428. events.failed = true;
  429. });
  430. disconnect(fail_ident);
  431. signal(events, "fail");
  432. });
  433. signal(events, "test");
  434. t.is(events.failed, undefined, 'disconnected slots do not fire');
  435. var sink = {f: function (ev) { this.ev = ev; }};
  436. var src = {};
  437. bindMethods(sink);
  438. connect(src, 'signal', sink.f);
  439. signal(src, 'signal', 'worked');
  440. t.is(sink.ev, 'worked', 'custom signal does not re-bind methods');
  441. var lateObj = { fun: function() { this.value = 1; } };
  442. connect(src, 'signal', lateObj, "fun");
  443. signal(src, 'signal');
  444. lateObj.fun = function() { this.value = 2; };
  445. signal(src, 'signal');
  446. t.is(lateObj.value, 2, 'connect uses late function binding');
  447. };