Added unit tests for setting offset one property at a time and added radix to parseIn...
[jquery.git] / test / unit / offset.js
1 module("offset");
2
3 testoffset("absolute"/* in iframe */, function($, iframe) {
4         expect(4);
5         
6         var doc = iframe.document, tests;
7         
8         // force a scroll value on the main window
9         // this insures that the results will be wrong
10         // if the offset method is using the scroll offset
11         // of the parent window
12         var forceScroll = jQuery('<div>', { width: 2000, height: 2000 }).appendTo('body');
13         window.scrollTo(1, 1);
14         
15         // get offset
16         tests = [
17                 { id: '#absolute-1', top: 1, left: 1 }
18         ];
19         jQuery.each( tests, function() {
20                 equals( jQuery( this.id, doc ).offset().top,  this.top,  "jQuery('" + this.id + "').offset().top" );
21                 equals( jQuery( this.id, doc ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
22         });
23
24
25         // get position
26         tests = [
27                 { id: '#absolute-1', top: 0, left: 0 }
28         ];
29         jQuery.each( tests, function() {
30                 equals( jQuery( this.id, doc ).position().top,  this.top,  "jQuery('" + this.id + "').position().top" );
31                 equals( jQuery( this.id, doc ).position().left, this.left, "jQuery('" + this.id + "').position().left" );
32         });
33         
34         forceScroll.remove();
35 });
36
37 testoffset("absolute", function( jQuery ) {
38         expect(176);
39         
40         // get offset tests
41         var tests = [
42                 { id: '#absolute-1',     top:  1, left:  1 }, 
43                 { id: '#absolute-1-1',   top:  5, left:  5 },
44                 { id: '#absolute-1-1-1', top:  9, left:  9 },
45                 { id: '#absolute-2',     top: 20, left: 20 }
46         ];
47         jQuery.each( tests, function() {
48                 equals( jQuery( this.id ).offset().top,  this.top,  "jQuery('" + this.id + "').offset().top" );
49                 equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
50         });
51         
52         
53         // get position
54         tests = [
55                 { id: '#absolute-1',     top:  0, left:  0 },
56                 { id: '#absolute-1-1',   top:  1, left:  1 },
57                 { id: '#absolute-1-1-1', top:  1, left:  1 },
58                 { id: '#absolute-2',     top: 19, left: 19 }
59         ];
60         jQuery.each( tests, function() {
61                 equals( jQuery( this.id ).position().top,  this.top,  "jQuery('" + this.id + "').position().top" );
62                 equals( jQuery( this.id ).position().left, this.left, "jQuery('" + this.id + "').position().left" );
63         });
64         
65         
66         // set offset
67         tests = [
68                 { id: '#absolute-2',     top: 30, left: 30 },
69                 { id: '#absolute-2',     top: 10, left: 10 },
70                 { id: '#absolute-2',     top: -1, left: -1 },
71                 { id: '#absolute-2',     top: 19, left: 19 },
72                 { id: '#absolute-1-1-1', top: 15, left: 15 },
73                 { id: '#absolute-1-1-1', top:  5, left:  5 },
74                 { id: '#absolute-1-1-1', top: -1, left: -1 },
75                 { id: '#absolute-1-1-1', top:  9, left:  9 },
76                 { id: '#absolute-1-1',   top: 10, left: 10 },
77                 { id: '#absolute-1-1',   top:  0, left:  0 },
78                 { id: '#absolute-1-1',   top: -1, left: -1 },
79                 { id: '#absolute-1-1',   top:  5, left:  5 },
80                 { id: '#absolute-1',     top:  2, left:  2 },
81                 { id: '#absolute-1',     top:  0, left:  0 },
82                 { id: '#absolute-1',     top: -1, left: -1 },
83                 { id: '#absolute-1',     top:  1, left:  1 }
84         ];
85         jQuery.each( tests, function() {
86                 jQuery( this.id ).offset({ top: this.top, left: this.left });
87                 equals( jQuery( this.id ).offset().top,  this.top,  "jQuery('" + this.id + "').offset({ top: "  + this.top  + " })" );
88                 equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
89                 
90                 var top = this.top, left = this.left;
91                 
92                 jQuery( this.id ).offset(function(i, val){
93                         equals( val.top, top, "Verify incoming top position." );
94                         equals( val.left, left, "Verify incoming top position." );
95                         return { top: top + 1, left: left + 1 };
96                 });
97                 equals( jQuery( this.id ).offset().top,  this.top  + 1, "jQuery('" + this.id + "').offset({ top: "  + (this.top  + 1) + " })" );
98                 equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + " })" );
99                 
100                 jQuery( this.id ).offset({ top: this.top + 2 });
101                 jQuery( this.id ).offset({ left: this.left + 2 });
102                 equals( jQuery( this.id ).offset().top,  this.top  + 2, "Setting one property at a time." );
103                 equals( jQuery( this.id ).offset().left, this.left + 2, "Setting one property at a time." );
104                 
105                 jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) {
106                         jQuery( this ).css({
107                                 top:  props.top  + 1,
108                                 left: props.left + 1
109                         });
110                 }});
111                 equals( jQuery( this.id ).offset().top,  this.top  + 1, "jQuery('" + this.id + "').offset({ top: "  + (this.top  + 1) + ", using: fn })" );
112                 equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + ", using: fn })" );
113         });
114 });
115
116 testoffset("relative", function( jQuery ) {
117         expect(60);
118         
119         // IE is collapsing the top margin of 1px
120         var ie = jQuery.browser.msie && parseInt( jQuery.browser.version, 10 ) < 8;
121         
122         // get offset
123         var tests = [
124                 { id: '#relative-1',   top: ie ?   6 :   7, left:  7 },
125                 { id: '#relative-1-1', top: ie ?  13 :  15, left: 15 },
126                 { id: '#relative-2',   top: ie ? 141 : 142, left: 27 }
127         ];
128         jQuery.each( tests, function() {
129                 equals( jQuery( this.id ).offset().top,  this.top,  "jQuery('" + this.id + "').offset().top" );
130                 equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
131         });
132         
133         
134         // get position
135         tests = [
136                 { id: '#relative-1',   top: ie ?   5 :   6, left:  6 },
137                 { id: '#relative-1-1', top: ie ?   4 :   5, left:  5 },
138                 { id: '#relative-2',   top: ie ? 140 : 141, left: 26 }
139         ];
140         jQuery.each( tests, function() {
141                 equals( jQuery( this.id ).position().top,  this.top,  "jQuery('" + this.id + "').position().top" );
142                 equals( jQuery( this.id ).position().left, this.left, "jQuery('" + this.id + "').position().left" );
143         });
144         
145         
146         // set offset
147         tests = [
148                 { id: '#relative-2',   top: 200, left:  50 },
149                 { id: '#relative-2',   top: 100, left:  10 },
150                 { id: '#relative-2',   top:  -5, left:  -5 },
151                 { id: '#relative-2',   top: 142, left:  27 },
152                 { id: '#relative-1-1', top: 100, left: 100 },
153                 { id: '#relative-1-1', top:   5, left:   5 },
154                 { id: '#relative-1-1', top:  -1, left:  -1 },
155                 { id: '#relative-1-1', top:  15, left:  15 },
156                 { id: '#relative-1',   top: 100, left: 100 },
157                 { id: '#relative-1',   top:   0, left:   0 },
158                 { id: '#relative-1',   top:  -1, left:  -1 },
159                 { id: '#relative-1',   top:   7, left:   7 }
160         ];
161         jQuery.each( tests, function() {
162                 jQuery( this.id ).offset({ top: this.top, left: this.left });
163                 equals( jQuery( this.id ).offset().top,  this.top,  "jQuery('" + this.id + "').offset({ top: "  + this.top  + " })" );
164                 equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
165                 
166                 jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) {
167                         jQuery( this ).css({
168                                 top:  props.top  + 1,
169                                 left: props.left + 1
170                         });
171                 }});
172                 equals( jQuery( this.id ).offset().top,  this.top  + 1, "jQuery('" + this.id + "').offset({ top: "  + (this.top  + 1) + ", using: fn })" );
173                 equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + ", using: fn })" );
174         });
175 });
176
177 testoffset("static", function( jQuery ) {
178         expect(80);
179         
180         // IE is collapsing the top margin of 1px
181         var ie = jQuery.browser.msie && parseInt( jQuery.browser.version, 10 ) < 8;
182         
183         // get offset
184         var tests = [
185                 { id: '#static-1',     top: ie ?   6 :   7, left:  7 },
186                 { id: '#static-1-1',   top: ie ?  13 :  15, left: 15 },
187                 { id: '#static-1-1-1', top: ie ?  20 :  23, left: 23 },
188                 { id: '#static-2',     top: ie ? 121 : 122, left:  7 }
189         ];
190         jQuery.each( tests, function() {
191                 equals( jQuery( this.id ).offset().top,  this.top,  "jQuery('" + this.id + "').offset().top" );
192                 equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
193         });
194         
195         
196         // get position
197         tests = [
198                 { id: '#static-1',     top: ie ?   5 :   6, left:  6 },
199                 { id: '#static-1-1',   top: ie ?  12 :  14, left: 14 },
200                 { id: '#static-1-1-1', top: ie ?  19 :  22, left: 22 },
201                 { id: '#static-2',     top: ie ? 120 : 121, left:  6 }
202         ];
203         jQuery.each( tests, function() {
204                 equals( jQuery( this.id ).position().top,  this.top,  "jQuery('" + this.top  + "').position().top" );
205                 equals( jQuery( this.id ).position().left, this.left, "jQuery('" + this.left +"').position().left" );
206         });
207         
208         
209         // set offset
210         tests = [
211                 { id: '#static-2',     top: 200, left: 200 },
212                 { id: '#static-2',     top: 100, left: 100 },
213                 { id: '#static-2',     top:  -2, left:  -2 },
214                 { id: '#static-2',     top: 121, left:   6 },
215                 { id: '#static-1-1-1', top:  50, left:  50 },
216                 { id: '#static-1-1-1', top:  10, left:  10 },
217                 { id: '#static-1-1-1', top:  -1, left:  -1 },
218                 { id: '#static-1-1-1', top:  22, left:  22 },
219                 { id: '#static-1-1',   top:  25, left:  25 },
220                 { id: '#static-1-1',   top:  10, left:  10 },
221                 { id: '#static-1-1',   top:  -3, left:  -3 },
222                 { id: '#static-1-1',   top:  14, left:  14 },
223                 { id: '#static-1',     top:  30, left:  30 },
224                 { id: '#static-1',     top:   2, left:   2 },
225                 { id: '#static-1',     top:  -2, left:  -2 },
226                 { id: '#static-1',     top:   7, left:   7 }
227         ];
228         jQuery.each( tests, function() {
229                 jQuery( this.id ).offset({ top: this.top, left: this.left });
230                 equals( jQuery( this.id ).offset().top,  this.top,  "jQuery('" + this.id + "').offset({ top: "  + this.top  + " })" );
231                 equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
232                 
233                 jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) {
234                         jQuery( this ).css({
235                                 top:  props.top  + 1,
236                                 left: props.left + 1
237                         });
238                 }});
239                 equals( jQuery( this.id ).offset().top,  this.top  + 1, "jQuery('" + this.id + "').offset({ top: "  + (this.top  + 1) + ", using: fn })" );
240                 equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + ", using: fn })" );
241         });
242 });
243
244 testoffset("fixed", function( jQuery ) {
245         expect(28);
246         
247         jQuery.offset.initialize();
248         
249         var tests = [
250                 { id: '#fixed-1', top: 1001, left: 1001 },
251                 { id: '#fixed-2', top: 1021, left: 1021 }
252         ];
253         jQuery.each( tests, function() {
254                 if ( jQuery.offset.supportsFixedPosition ) {
255                         equals( jQuery( this.id ).offset().top,  this.top,  "jQuery('" + this.id + "').offset().top" );
256                         equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
257                 } else {
258                         // need to have same number of assertions
259                         ok( true, 'Fixed position is not supported' );
260                         ok( true, 'Fixed position is not supported' );
261                 }
262         });
263         
264         tests = [
265                 { id: '#fixed-1', top: 100, left: 100 },
266                 { id: '#fixed-1', top:   0, left:   0 },
267                 { id: '#fixed-1', top:  -4, left:  -4 },
268                 { id: '#fixed-2', top: 200, left: 200 },
269                 { id: '#fixed-2', top:   0, left:   0 },
270                 { id: '#fixed-2', top:  -5, left:  -5 }
271         ];
272         
273         jQuery.each( tests, function() {
274                 if ( jQuery.offset.supportsFixedPosition ) {
275                         jQuery( this.id ).offset({ top: this.top, left: this.left });
276                         equals( jQuery( this.id ).offset().top,  this.top,  "jQuery('" + this.id + "').offset({ top: "  + this.top  + " })" );
277                         equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
278                 
279                         jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) {
280                                 jQuery( this ).css({
281                                         top:  props.top  + 1,
282                                         left: props.left + 1
283                                 });
284                         }});
285                         equals( jQuery( this.id ).offset().top,  this.top  + 1, "jQuery('" + this.id + "').offset({ top: "  + (this.top  + 1) + ", using: fn })" );
286                         equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + ", using: fn })" );
287                 } else {
288                         // need to have same number of assertions
289                         ok( true, 'Fixed position is not supported' );
290                         ok( true, 'Fixed position is not supported' );
291                         ok( true, 'Fixed position is not supported' );
292                         ok( true, 'Fixed position is not supported' );
293                 }
294         });
295 });
296
297 testoffset("table", function( jQuery ) {
298         expect(4);
299         
300         equals( jQuery('#table-1').offset().top, 6, "jQuery('#table-1').offset().top" );
301         equals( jQuery('#table-1').offset().left, 6, "jQuery('#table-1').offset().left" );
302         
303         equals( jQuery('#th-1').offset().top, 10, "jQuery('#th-1').offset().top" );
304         equals( jQuery('#th-1').offset().left, 10, "jQuery('#th-1').offset().left" );
305 });
306
307 testoffset("scroll", function( jQuery, win ) {
308         expect(16);
309         
310         var ie = jQuery.browser.msie && parseInt( jQuery.browser.version, 10 ) < 8;
311         
312         // IE is collapsing the top margin of 1px
313         equals( jQuery('#scroll-1').offset().top, ie ? 6 : 7, "jQuery('#scroll-1').offset().top" );
314         equals( jQuery('#scroll-1').offset().left, 7, "jQuery('#scroll-1').offset().left" );
315         
316         // IE is collapsing the top margin of 1px
317         equals( jQuery('#scroll-1-1').offset().top, ie ? 9 : 11, "jQuery('#scroll-1-1').offset().top" );
318         equals( jQuery('#scroll-1-1').offset().left, 11, "jQuery('#scroll-1-1').offset().left" );
319         
320         
321         // scroll offset tests .scrollTop/Left
322         equals( jQuery('#scroll-1').scrollTop(), 5, "jQuery('#scroll-1').scrollTop()" );
323         equals( jQuery('#scroll-1').scrollLeft(), 5, "jQuery('#scroll-1').scrollLeft()" );
324         
325         equals( jQuery('#scroll-1-1').scrollTop(), 0, "jQuery('#scroll-1-1').scrollTop()" );
326         equals( jQuery('#scroll-1-1').scrollLeft(), 0, "jQuery('#scroll-1-1').scrollLeft()" );
327         
328         // equals( jQuery('body').scrollTop(), 0, "jQuery('body').scrollTop()" );
329         // equals( jQuery('body').scrollLeft(), 0, "jQuery('body').scrollTop()" );
330         
331         win.name = "test";
332         
333         equals( jQuery(win).scrollTop(), 1000, "jQuery(window).scrollTop()" );
334         equals( jQuery(win).scrollLeft(), 1000, "jQuery(window).scrollLeft()" );
335         
336         equals( jQuery(win.document).scrollTop(), 1000, "jQuery(document).scrollTop()" );
337         equals( jQuery(win.document).scrollLeft(), 1000, "jQuery(document).scrollLeft()" );
338         
339         // test jQuery using parent window/document
340         // jQuery reference here is in the iframe
341         window.scrollTo(0,0);
342         equals( jQuery(window).scrollTop(), 0, "jQuery(window).scrollTop() other window" );
343         equals( jQuery(window).scrollLeft(), 0, "jQuery(window).scrollLeft() other window" );
344         equals( jQuery(document).scrollTop(), 0, "jQuery(window).scrollTop() other document" );
345         equals( jQuery(document).scrollLeft(), 0, "jQuery(window).scrollLeft() other document" );
346 });
347
348 testoffset("body", function( jQuery ) {
349         expect(2);
350         
351         equals( jQuery('body').offset().top, 1, "jQuery('#body').offset().top" );
352         equals( jQuery('body').offset().left, 1, "jQuery('#body').offset().left" );
353 });
354
355 test("Chaining offset(coords) returns jQuery object", function() {
356         expect(2);
357         var coords = { top:  1, left:  1 };
358         equals( jQuery("#absolute-1").offset(coords).selector, "#absolute-1", "offset(coords) returns jQuery object" );
359         equals( jQuery("#non-existent").offset(coords).selector, "#non-existent", "offset(coords) with empty jQuery set returns jQuery object" );
360 });
361
362 test("offsetParent", function(){
363         expect(11);
364
365         var body = jQuery("body").offsetParent();
366         equals( body.length, 1, "Only one offsetParent found." );
367         equals( body[0], document.body, "The body is its own offsetParent." );
368
369         var header = jQuery("#qunit-header").offsetParent();
370         equals( header.length, 1, "Only one offsetParent found." );
371         equals( header[0], document.body, "The body is the offsetParent." );
372
373         var div = jQuery("#nothiddendivchild").offsetParent();
374         equals( div.length, 1, "Only one offsetParent found." );
375         equals( div[0], document.body, "The body is the offsetParent." );
376
377         jQuery("#nothiddendiv").css("position", "relative");
378
379         div = jQuery("#nothiddendivchild").offsetParent();
380         equals( div.length, 1, "Only one offsetParent found." );
381         equals( div[0], jQuery("#nothiddendiv")[0], "The div is the offsetParent." );
382
383         div = jQuery("body, #nothiddendivchild").offsetParent();
384         equals( div.length, 2, "Two offsetParent found." );
385         equals( div[0], document.body, "The body is the offsetParent." );
386         equals( div[1], jQuery("#nothiddendiv")[0], "The div is the offsetParent." );
387 });
388
389 function testoffset(name, fn) {
390         
391         test(name, function() {
392                 // pause execution for now
393                 stop();
394                 
395                 // load fixture in iframe
396                 var iframe = loadFixture(),
397                         win = iframe.contentWindow,
398                         interval = setInterval( function() {
399                                 if ( win && win.jQuery && win.jQuery.isReady ) {
400                                         clearInterval( interval );
401                                         // continue
402                                         start();
403                                         // call actual tests passing the correct jQuery isntance to use
404                                         fn.call( this, win.jQuery, win );
405                                         document.body.removeChild( iframe );
406                                         iframe = null;
407                                 }
408                         }, 15 );
409         });
410         
411         function loadFixture() {
412                 var src = './data/offset/' + name + '.html?' + parseInt( Math.random()*1000, 10 ),
413                         iframe = jQuery('<iframe />').css({
414                                 width: 500, height: 500, position: 'absolute', top: -600, left: -600, visiblity: 'hidden'
415                         }).appendTo('body')[0];
416                 iframe.contentWindow.location = src;
417                 return iframe;
418         }
419 }