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