added Tom Marble's slides
[lp17-speaker-slides.git] / Tom-Marble / deck.js / test / spec.core.js
1 // Go tests, go
2 describe('Deck JS', function() {
3 describe('standard html structure', function() {
4 beforeEach(function() {
5 loadFixtures('standard.html');
6 if (Modernizr.history) {
7 history.replaceState({}, "", "#")
8 }
9 else {
10 window.location.hash = '#';
11 }
12 });
13
14 describe('init(options.selectors.slides)', function() {
15 it('should create slides', function() {
16 $.deck({
17 selectors: {
18 slides: '.slide3'
19 }
20 });
21 expect($.deck('getSlides').length).toEqual($('.slide3').length);
22 });
23 });
24
25 describe('init(selector)', function() {
26 it('should create slides', function() {
27 $.deck();
28 expect($.deck('getSlides').length).toEqual($('.slide').length);
29 });
30 });
31
32 describe('init([selectors])', function() {
33 it('should create slides', function() {
34 $.deck([
35 '.slide1',
36 '.slide2',
37 '.slide3',
38 '.slide4',
39 '.slide5'
40 ]);
41 expect($.deck('getSlides').length).toEqual($('.slide').length);
42 });
43 });
44
45 describe('navigation functions', function() {
46 beforeEach(function() {
47 $.deck();
48 });
49
50 describe('go(i)', function() {
51 it('should go to the i slide (0 based index)', function() {
52 $.deck('go', 3);
53 expect($.deck('getSlide')).toHaveClass('slide4');
54 });
55
56 it('should go to the slide with specified id', function() {
57 $.deck('go', 'custom-id');
58 expect($.deck('getSlide')).toHaveId('custom-id');
59 });
60
61 it('should go nowhere if i is out of bounds', function() {
62 $.deck('go', 5);
63 expect($.deck('getSlide')).toHaveClass('slide1');
64 });
65
66 it('should go nowhere if id does not exist', function() {
67 $.deck('go', 'i-dont-exist');
68 expect($.deck('getSlide')).toHaveClass('slide1');
69 });
70
71 describe('aria attribute updates', function() {
72 beforeEach(function() {
73 loadFixtures('nesteds.html');
74 $.deck();
75 $.deck('go', 5);
76 });
77
78 it('should set offscreen slides to hidden true', function() {
79 $([
80 '.toplevel.deck-before:not(.deck-child-current)',
81 '.toplevel.deck-previous:not(.deck-child-current)',
82 '.deck-next',
83 '.deck-after'
84 ].join(', ')).each(function() {
85 expect($(this)).toHaveAttr('aria-hidden', 'true');
86 });
87 });
88
89 it('should set onscreen slides to hidden false', function() {
90 $([
91 '.deck-child-current.slide',
92 '.deck-child-current .deck-before',
93 '.deck-child-current .deck-previous',
94 '.deck-current'
95 ].join(', ')).each(function() {
96 expect($(this)).toHaveAttr('aria-hidden', 'false');
97 });
98 });
99 });
100 });
101
102 describe('next()', function() {
103 it('should go to the next slide', function() {
104 $.deck('next');
105 expect($.deck('getSlide')).toHaveClass('slide2');
106 });
107
108 it('should go nowhere if on the last slide', function() {
109 $.deck('go', 4);
110 $.deck('next');
111 expect($.deck('getSlide')).toHaveClass('slide5');
112 });
113 });
114
115 describe('prev()', function() {
116 it('should go to the previous slide', function() {
117 $.deck('go', 2);
118 $.deck('prev');
119 expect($.deck('getSlide')).toHaveClass('slide2');
120 });
121
122 it('should go nowhere if on the first slide', function() {
123 $.deck('prev');
124 expect($.deck('getSlide')).toHaveClass('slide1');
125 });
126 });
127 });
128
129 describe('getters', function() {
130 beforeEach(function() {
131 $.deck();
132 });
133
134 describe('getSlide()', function() {
135 it('should get the current slide', function() {
136 expect($.deck('getSlide')).toHaveClass('slide1');
137 $.deck('go', 2);
138 expect($.deck('getSlide')).toHaveClass('slide3');
139 });
140 });
141
142 describe('getSlide(i)', function() {
143 it('should get slide number i (0 based index)', function() {
144 expect($.deck('getSlide', 1)).toHaveClass('slide2');
145 expect($.deck('getSlide', 3)).toHaveClass('slide4');
146 });
147
148 it('should return null if i is NaN', function() {
149 expect($.deck('getSlide', 'barfoo')).toBeNull();
150 });
151
152 it('should return null if i is out of bounds', function() {
153 expect($.deck('getSlide', 6)).toBeNull();
154 });
155 });
156
157 describe('getSlides()', function() {
158 it('should return an array of jQuery objects for each slide', function() {
159 var expectation = [];
160 var slides = $.deck('getSlides');
161 $('.slide').each(function() {
162 expectation.push($(this));
163 });
164 expect(slides).toEqual(expectation);
165 });
166 });
167
168 describe('getContainer()', function() {
169 it('should return a jQuery object with the container element(s)', function() {
170 expect($.deck('getContainer')).toBe(defaults.selectors.container);
171 });
172 });
173
174 describe('getOptions()', function() {
175 it('should return the current options object', function() {
176 expect($.deck('getOptions')).toEqual(defaults);
177 });
178 });
179
180 describe('getTopLevelSlides()', function() {
181 it('should return only root slides', function() {
182 loadFixtures('nesteds.html');
183 $.deck();
184 var expectation = [];
185 var topLevelSlides = $.deck('getTopLevelSlides');
186 $('.toplevel').each(function() {
187 expectation.push($(this));
188 });
189 expect(topLevelSlides).toEqual(expectation);
190 });
191 });
192
193 describe('getNestedSlides()', function() {
194 it('should return nested slides for current slide', function() {
195 loadFixtures('nesteds.html');
196 $.deck();
197 $.deck('go', 2);
198 var expectation = [];
199 var nestedSlides = $.deck('getNestedSlides');
200 $.deck('getSlide').find('.slide').each(function() {
201 expectation.push($(this));
202 });
203 expect(nestedSlides).toEqual(expectation);
204 });
205 });
206 });
207
208 describe('container states', function() {
209 beforeEach(function() {
210 $.deck();
211 });
212
213 it('should start at state 0', function() {
214 expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '0');
215 });
216
217 it('should change states with the slide number', function() {
218 $.deck('next');
219 expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '1');
220 $.deck('go', 3);
221 expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '3');
222 $.deck('prev');
223 expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '2');
224 });
225 });
226
227 describe('options object', function() {
228 var $d = $(document);
229
230 beforeEach(function() {
231 $.deck('.alt-slide', {
232 classes: {
233 after: 'alt-after',
234 before: 'alt-before',
235 current: 'alt-current',
236 onPrefix: 'alt-on-',
237 next: 'alt-next',
238 previous: 'alt-prev'
239 },
240
241 selectors: {
242 container: '.alt-container'
243 },
244
245 keys: {
246 next: 87,
247 previous: 69
248 }
249 });
250 });
251
252 describe('classes', function() {
253 it('should use the specified after class', function() {
254 expect($('.alt-slide3, .alt-slide4, .alt-slide5')).toHaveClass('alt-after');
255 });
256
257 it('should use the specified before class', function() {
258 $.deck('go', 4);
259 expect($('.alt-slide1, .alt-slide2, .alt-slide3')).toHaveClass('alt-before');
260 });
261
262 it('should use the specified container class', function() {
263 $.deck('go', 2);
264 expect($('.alt-container')).toHaveClass('alt-on-2');
265 });
266
267 it('should use the specified current class', function() {
268 expect($.deck('getSlide')).toHaveClass('alt-current');
269 });
270
271 it('should use the specified next class', function() {
272 expect($('.alt-slide2')).toHaveClass('alt-next');
273 });
274
275 it('should use the specified previous class', function() {
276 $.deck('next');
277 expect($('.alt-slide1')).toHaveClass('alt-prev');
278 });
279 });
280
281 describe('key bindings', function() {
282 var e;
283
284 beforeEach(function() {
285 e = jQuery.Event('keydown.deck');
286 });
287
288 it('should go to the next slide using the specified key', function() {
289 e.which = 87; // 'w'
290 $d.trigger(e);
291 expect($.deck('getSlide')).toHaveClass('alt-slide2');
292 });
293
294 it('should go to the previous slide using the specified key', function() {
295 $.deck('next');
296 e.which = 69; // 'e'
297 $d.trigger(e);
298 expect($.deck('getSlide')).toHaveClass('alt-slide1');
299 });
300
301 it('should not trigger events that originate within editable elements', function() {
302 var $outside = $('<input type="text" />').appendTo('body');
303 e = jQuery.Event('keydown');
304 e.which = 87;
305 $outside.trigger(e);
306 expect($.deck('getSlide')).toHaveClass('alt-slide1');
307 $outside.remove();
308 });
309 });
310 });
311
312 describe('events', function() {
313 var $d;
314
315 beforeEach(function() {
316 $d = $(document);
317 });
318
319 describe('deck.change', function() {
320 var index, oldIndex;
321
322 beforeEach(function() {
323 $.deck();
324 $.deck('go', 1);
325 $d.one('deck.change', function(event, from, to) {
326 index = to;
327 oldIndex = from;
328 });
329 });
330
331 it('should fire on go(i)', function() {
332 $.deck('go', 3);
333 expect(index).toEqual(3);
334 });
335
336 it('should fire on next()', function() {
337 $.deck('next');
338 expect(index).toEqual(2);
339 });
340
341 it('should fire on prev()', function() {
342 $.deck('prev');
343 expect(index).toEqual(0);
344 });
345
346 it('should pass parameters with from and to indices', function() {
347 $.deck('go', 3);
348 expect(index).toEqual(3);
349 expect(oldIndex).toEqual(1);
350 });
351
352 it('should not fire if default prevented in beforeChange', function() {
353 $d.bind('deck.beforeChange', false);
354 $.deck('go', 3);
355 expect($.deck('getSlide')).toEqual($.deck('getSlide', 1));
356 $d.unbind('deck.beforeChange', false);
357 });
358 });
359
360 describe('deck.init', function() {
361 it('should fire on deck initialization', function() {
362 $.deck();
363 expect($.deck('getSlides').length).toBeGreaterThan(0);
364 });
365 });
366
367 describe('deck.beforeInit', function() {
368 var beforeHit;
369
370 beforeEach(function() {
371 beforeHit = false;
372 $d.on('deck.beforeInit', function() {
373 beforeHit = true;
374 });
375 });
376
377 it('should fire on deck initialization', function() {
378 $.deck();
379 expect(beforeHit).toBeTruthy();
380 });
381
382 it('should have populated the slides array', function() {
383 var f = function() {
384 expect($.deck('getSlides').length).toEqual($('.slide').length);
385 };
386
387 $d.bind('deck.beforeInit', f);
388 $.deck();
389 $d.unbind('deck.beforeInit', f);
390 });
391
392 it('should prevent the init event if lockInit is called', function() {
393 var initHit = false;
394 var f = function(event) {
395 event.lockInit();
396 };
397 var g = function() {
398 initHit = true;
399 };
400
401 $d.bind('deck.beforeInit', f);
402 $d.bind('deck.init', g);
403 $.deck();
404 $d.unbind('deck.beforeInit', f);
405 $d.unbind('deck.init', g);
406 expect(initHit).toBeFalsy();
407 });
408
409 it('should warn if locked without release', function() {
410 var warned = false;
411 var f = function(event) {
412 event.lockInit();
413 };
414 var warn = console.warn;
415 window.console.warn = function() {
416 warned = true;
417 };
418
419 $d.bind('deck.beforeInit', f);
420 $.deck('.slide', {
421 initLockTimeout: 20
422 });
423 $d.unbind('deck.beforeInit', f);
424
425 waitsFor(function() {
426 return warned;
427 }, 'warning', 2000);
428
429 runs(function() {
430 window.console.warn = warn;
431 });
432 });
433
434 it('should fire init event once releaseInit is called', function() {
435 var f = function(event) {
436 event.lockInit();
437 window.setTimeout(function() {
438 event.releaseInit();
439 }, 20);
440 };
441
442 runs(function() {
443 $d.bind('deck.beforeInit', f);
444 $.deck();
445 $d.unbind('deck.beforeInit', f);
446 });
447
448 waitsFor(function() {
449 return $.deck('getSlides').length > 0;
450 }, 'lock to release', 2000);
451 });
452 });
453 });
454
455 describe('hash/id assignments', function() {
456 beforeEach(function() {
457 $.deck('.slide');
458 });
459
460 it('should assign ids to slides that do not have them', function() {
461 var slides = $.deck('getSlides');
462 $.each(slides, function(i, $e) {
463 expect($e.attr('id')).toBeTruthy();
464 });
465 });
466
467 it('should reassign ids on reinitialization', function() {
468 var $firstSlide = $.deck('getSlide', 0);
469 var firstID = $firstSlide.attr('id');
470
471 $firstSlide.before('<div class="slide"></div>');
472 $.deck('.slide');
473 expect($firstSlide).not.toHaveId(firstID);
474 });
475
476 it('should update container with a state class including the slide id', function() {
477 var $c = $.deck('getContainer');
478 var osp = defaults.classes.onPrefix;
479
480 expect($c).toHaveClass(osp + $.deck('getSlide', 0).attr('id'));
481 $.deck('next');
482 expect($c).toHaveClass(osp + $.deck('getSlide', 1).attr('id'));
483 $.deck('next');
484 expect($c).not.toHaveClass(osp + $.deck('getSlide', 1).attr('id'));
485 expect($c).toHaveClass(osp + $.deck('getSlide', 2).attr('id'));
486 });
487
488 it('should use existing ids if they exist', function() {
489 expect($('#custom-id')).toExist();
490 });
491
492 it('should update the URL on slide change (if supported)', function() {
493 if (Modernizr.history) {
494 $.deck('go', 3);
495 expect(window.location.hash).toEqual('#slide-3');
496 }
497 });
498
499 it('should deep link to slide on deck init', function() {
500 window.location.hash = "#slide-3";
501 $.deck('.slide');
502 waitsFor(function() {
503 return $.deck('getSlide').attr('id') === 'slide-3';
504 });
505 });
506
507 it('should follow internal hash links using hashchange (if supported)', function() {
508 window.location.hash = "#slide-3";
509 // Hashchange event doesn't fire right when the hash changes?
510 waitsFor(function() {
511 return $.deck('getSlide').attr('id') === 'slide-3';
512 }, 'hash to change to slide-3', 2000);
513 });
514 });
515 });
516
517 describe('empty deck', function() {
518 beforeEach(function() {
519 loadFixtures('empty.html');
520 $.deck();
521 });
522
523 describe('getSlide()', function() {
524 it('should not error on init', $.noop);
525 });
526 });
527 });