PageRenderTime 71ms CodeModel.GetById 14ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 1ms

/tests/test_Signal.js

https://github.com/schuyler1d/mochikit-mirror
JavaScript | 527 lines | 426 code | 90 blank | 11 comment | 19 complexity | 01b302b990d81c84e9598ed4e5fec62a 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('signalOne');
440    disconnectAll('signalTwo');
441
442    var testfunc = function () { arguments.callee.count++; };
443    testfunc.count = 0;
444    var testObj = {
445        methOne: function () { this.countOne++; }, countOne: 0,
446        methTwo: function () { this.countTwo++; }, countTwo: 0
447    };
448    connect(hasSignals, 'signalOne', testfunc);
449    connect(hasSignals, 'signalTwo', testfunc);
450    signal(hasSignals, 'signalOne');
451    signal(hasSignals, 'signalTwo');
452    t.is(testfunc.count, 2, 'disconnectAllTo func precondition');
453    disconnectAllTo(testfunc);
454    signal(hasSignals, 'signalOne');
455    signal(hasSignals, 'signalTwo');
456    t.is(testfunc.count, 2, 'disconnectAllTo func');
457
458    connect(hasSignals, 'signalOne', testObj, 'methOne');
459    connect(hasSignals, 'signalTwo', testObj, 'methTwo');
460    signal(hasSignals, 'signalOne');
461    signal(hasSignals, 'signalTwo');
462    t.is(testObj.countOne, 1, 'disconnectAllTo obj precondition');
463    t.is(testObj.countTwo, 1, 'disconnectAllTo obj precondition');
464    disconnectAllTo(testObj);
465    signal(hasSignals, 'signalOne');
466    signal(hasSignals, 'signalTwo');
467    t.is(testObj.countOne, 1, 'disconnectAllTo obj');
468    t.is(testObj.countTwo, 1, 'disconnectAllTo obj');
469
470    testObj.countOne = testObj.countTwo = 0;
471    connect(hasSignals, 'signalOne', testObj, 'methOne');
472    connect(hasSignals, 'signalTwo', testObj, 'methTwo');
473    disconnectAllTo(testObj, 'methOne');
474    signal(hasSignals, 'signalOne');
475    signal(hasSignals, 'signalTwo');
476    t.is(testObj.countOne, 0, 'disconnectAllTo obj+str');
477    t.is(testObj.countTwo, 1, 'disconnectAllTo obj+str');
478
479    var has__Connect = {
480          count: 0,
481          __connect__: function (ident) {
482              this.count += arguments.length;
483              disconnect(ident);
484          }
485    };
486    connect(has__Connect, 'signalOne', function() {
487        t.fail("__connect__ should have disconnected signal");
488    });
489    t.is(has__Connect.count, 3, '__connect__ is called when it exists');
490    signal(has__Connect, 'signalOne');
491
492    var has__Disconnect = {
493          count: 0,
494          __disconnect__: function (ident) {
495              this.count += arguments.length;
496          }
497    };
498    connect(has__Disconnect, 'signalOne', aFunction);
499    connect(has__Disconnect, 'signalTwo', aFunction);
500    disconnectAll(has__Disconnect);
501    t.is(has__Disconnect.count, 8, '__disconnect__ is called when it exists');
502
503    var events = {};
504    var test_ident = connect(events, "test", function() {
505        var fail_ident = connect(events, "fail", function () {
506            events.failed = true;
507        });
508        disconnect(fail_ident);
509        signal(events, "fail");
510    });
511    signal(events, "test");
512    t.is(events.failed, undefined, 'disconnected slots do not fire');
513
514    var sink = {f: function (ev) { this.ev = ev; }};
515    var src = {};
516    bindMethods(sink);
517    connect(src, 'signal', sink.f);
518    signal(src, 'signal', 'worked');
519    t.is(sink.ev, 'worked', 'custom signal does not re-bind methods');
520
521    var lateObj = { fun: function() { this.value = 1; } };
522    connect(src, 'signal', lateObj, "fun");
523    signal(src, 'signal');
524    lateObj.fun = function() { this.value = 2; };
525    signal(src, 'signal');
526    t.is(lateObj.value, 2, 'connect uses late function binding');
527};