Merge "resources: Strip '$' and 'mw' from file closures"
[lhc/web/wiklou.git] / tests / qunit / suites / resources / jquery / jquery.makeCollapsible.test.js
1 ( function () {
2 var loremIpsum = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.';
3
4 QUnit.module( 'jquery.makeCollapsible', QUnit.newMwEnvironment() );
5
6 function prepareCollapsible( html, options ) {
7 return $( $.parseHTML( html ) )
8 .appendTo( '#qunit-fixture' )
9 // options might be undefined here - this is okay
10 .makeCollapsible( options );
11 }
12
13 // This test is first because if it fails, then almost all of the latter tests are meaningless.
14 QUnit.test( 'testing hooks/triggers', function ( assert ) {
15 var $collapsible = prepareCollapsible(
16 '<div class="mw-collapsible">' + loremIpsum + '</div>'
17 ),
18 $content = $collapsible.find( '.mw-collapsible-content' ),
19 $toggle = $collapsible.find( '.mw-collapsible-toggle' );
20
21 // In one full collapse-expand cycle, each event will be fired once
22
23 // On collapse...
24 $collapsible.on( 'beforeCollapse.mw-collapsible', function () {
25 assert.assertTrue( $content.is( ':visible' ), 'first beforeCollapseExpand: content is visible' );
26 } );
27 $collapsible.on( 'afterCollapse.mw-collapsible', function () {
28 assert.assertTrue( $content.is( ':hidden' ), 'first afterCollapseExpand: content is hidden' );
29
30 // On expand...
31 $collapsible.on( 'beforeExpand.mw-collapsible', function () {
32 assert.assertTrue( $content.is( ':hidden' ), 'second beforeCollapseExpand: content is hidden' );
33 } );
34 $collapsible.on( 'afterExpand.mw-collapsible', function () {
35 assert.assertTrue( $content.is( ':visible' ), 'second afterCollapseExpand: content is visible' );
36 } );
37
38 // ...expanding happens here
39 $toggle.trigger( 'click' );
40 } );
41
42 // ...collapsing happens here
43 $toggle.trigger( 'click' );
44 } );
45
46 QUnit.test( 'basic operation (<div>)', function ( assert ) {
47 var $collapsible = prepareCollapsible(
48 '<div class="mw-collapsible">' + loremIpsum + '</div>'
49 ),
50 $content = $collapsible.find( '.mw-collapsible-content' ),
51 $toggle = $collapsible.find( '.mw-collapsible-toggle' );
52
53 assert.strictEqual( $content.length, 1, 'content is present' );
54 assert.strictEqual( $content.find( $toggle ).length, 0, 'toggle is not a descendant of content' );
55
56 assert.assertTrue( $content.is( ':visible' ), 'content is visible' );
57
58 $collapsible.on( 'afterCollapse.mw-collapsible', function () {
59 assert.assertTrue( $content.is( ':hidden' ), 'after collapsing: content is hidden' );
60
61 $collapsible.on( 'afterExpand.mw-collapsible', function () {
62 assert.assertTrue( $content.is( ':visible' ), 'after expanding: content is visible' );
63 } );
64
65 $toggle.trigger( 'click' );
66 } );
67
68 $toggle.trigger( 'click' );
69 } );
70
71 QUnit.test( 'basic operation (<table>)', function ( assert ) {
72 var $collapsible = prepareCollapsible(
73 '<table class="mw-collapsible">' +
74 '<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
75 '<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
76 '<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
77 '</table>'
78 ),
79 $headerRow = $collapsible.find( 'tr:first' ),
80 $contentRow = $collapsible.find( 'tr:last' ),
81 $toggle = $headerRow.find( 'td:last .mw-collapsible-toggle' );
82
83 assert.strictEqual( $toggle.length, 1, 'toggle is added to last cell of first row' );
84
85 assert.assertTrue( $headerRow.is( ':visible' ), 'headerRow is visible' );
86 assert.assertTrue( $contentRow.is( ':visible' ), 'contentRow is visible' );
87
88 $collapsible.on( 'afterCollapse.mw-collapsible', function () {
89 assert.assertTrue( $headerRow.is( ':visible' ), 'after collapsing: headerRow is still visible' );
90 assert.assertTrue( $contentRow.is( ':hidden' ), 'after collapsing: contentRow is hidden' );
91
92 $collapsible.on( 'afterExpand.mw-collapsible', function () {
93 assert.assertTrue( $headerRow.is( ':visible' ), 'after expanding: headerRow is still visible' );
94 assert.assertTrue( $contentRow.is( ':visible' ), 'after expanding: contentRow is visible' );
95 } );
96
97 $toggle.trigger( 'click' );
98 } );
99
100 $toggle.trigger( 'click' );
101 } );
102
103 function tableWithCaptionTest( $collapsible, test, assert ) {
104 var $caption = $collapsible.find( 'caption' ),
105 $headerRow = $collapsible.find( 'tr:first' ),
106 $contentRow = $collapsible.find( 'tr:last' ),
107 $toggle = $caption.find( '.mw-collapsible-toggle' );
108
109 assert.strictEqual( $toggle.length, 1, 'toggle is added to the end of the caption' );
110
111 assert.assertTrue( $caption.is( ':visible' ), 'caption is visible' );
112 assert.assertTrue( $headerRow.is( ':visible' ), 'headerRow is visible' );
113 assert.assertTrue( $contentRow.is( ':visible' ), 'contentRow is visible' );
114
115 $collapsible.on( 'afterCollapse.mw-collapsible', function () {
116 assert.assertTrue( $caption.is( ':visible' ), 'after collapsing: caption is still visible' );
117 assert.assertTrue( $headerRow.is( ':hidden' ), 'after collapsing: headerRow is hidden' );
118 assert.assertTrue( $contentRow.is( ':hidden' ), 'after collapsing: contentRow is hidden' );
119
120 $collapsible.on( 'afterExpand.mw-collapsible', function () {
121 assert.assertTrue( $caption.is( ':visible' ), 'after expanding: caption is still visible' );
122 assert.assertTrue( $headerRow.is( ':visible' ), 'after expanding: headerRow is visible' );
123 assert.assertTrue( $contentRow.is( ':visible' ), 'after expanding: contentRow is visible' );
124 } );
125
126 $toggle.trigger( 'click' );
127 } );
128
129 $toggle.trigger( 'click' );
130 }
131
132 QUnit.test( 'basic operation (<table> with caption)', function ( assert ) {
133 tableWithCaptionTest( prepareCollapsible(
134 '<table class="mw-collapsible">' +
135 '<caption>' + loremIpsum + '</caption>' +
136 '<tr><th>' + loremIpsum + '</th><th>' + loremIpsum + '</th></tr>' +
137 '<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
138 '<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
139 '</table>'
140 ), this, assert );
141 } );
142
143 QUnit.test( 'basic operation (<table> with caption and <thead>)', function ( assert ) {
144 tableWithCaptionTest( prepareCollapsible(
145 '<table class="mw-collapsible">' +
146 '<caption>' + loremIpsum + '</caption>' +
147 '<thead><tr><th>' + loremIpsum + '</th><th>' + loremIpsum + '</th></tr></thead>' +
148 '<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
149 '<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
150 '</table>'
151 ), this, assert );
152 } );
153
154 function listTest( listType, test, assert ) {
155 var $collapsible = prepareCollapsible(
156 '<' + listType + ' class="mw-collapsible">' +
157 '<li>' + loremIpsum + '</li>' +
158 '<li>' + loremIpsum + '</li>' +
159 '</' + listType + '>'
160 ),
161 $toggleItem = $collapsible.find( 'li.mw-collapsible-toggle-li:first-child' ),
162 $contentItem = $collapsible.find( 'li:last' ),
163 $toggle = $toggleItem.find( '.mw-collapsible-toggle' );
164
165 assert.strictEqual( $toggle.length, 1, 'toggle is present, added inside new zeroth list item' );
166
167 assert.assertTrue( $toggleItem.is( ':visible' ), 'toggleItem is visible' );
168 assert.assertTrue( $contentItem.is( ':visible' ), 'contentItem is visible' );
169
170 $collapsible.on( 'afterCollapse.mw-collapsible', function () {
171 assert.assertTrue( $toggleItem.is( ':visible' ), 'after collapsing: toggleItem is still visible' );
172 assert.assertTrue( $contentItem.is( ':hidden' ), 'after collapsing: contentItem is hidden' );
173
174 $collapsible.on( 'afterExpand.mw-collapsible', function () {
175 assert.assertTrue( $toggleItem.is( ':visible' ), 'after expanding: toggleItem is still visible' );
176 assert.assertTrue( $contentItem.is( ':visible' ), 'after expanding: contentItem is visible' );
177 } );
178
179 $toggle.trigger( 'click' );
180 } );
181
182 $toggle.trigger( 'click' );
183 }
184
185 QUnit.test( 'basic operation (<ul>)', function ( assert ) {
186 listTest( 'ul', this, assert );
187 } );
188
189 QUnit.test( 'basic operation (<ol>)', function ( assert ) {
190 listTest( 'ol', this, assert );
191 } );
192
193 QUnit.test( 'basic operation when synchronous (options.instantHide)', function ( assert ) {
194 var $collapsible = prepareCollapsible(
195 '<div class="mw-collapsible">' + loremIpsum + '</div>',
196 { instantHide: true }
197 ),
198 $content = $collapsible.find( '.mw-collapsible-content' );
199
200 assert.assertTrue( $content.is( ':visible' ), 'content is visible' );
201
202 $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
203
204 assert.assertTrue( $content.is( ':hidden' ), 'after collapsing: content is hidden' );
205 } );
206
207 QUnit.test( 'mw-made-collapsible data added', function ( assert ) {
208 var $collapsible = prepareCollapsible(
209 '<div>' + loremIpsum + '</div>'
210 );
211
212 assert.strictEqual( $collapsible.data( 'mw-made-collapsible' ), true, 'mw-made-collapsible data present' );
213 } );
214
215 QUnit.test( 'mw-collapsible added when missing', function ( assert ) {
216 var $collapsible = prepareCollapsible(
217 '<div>' + loremIpsum + '</div>'
218 );
219
220 assert.assertTrue( $collapsible.hasClass( 'mw-collapsible' ), 'mw-collapsible class present' );
221 } );
222
223 QUnit.test( 'mw-collapsed added when missing', function ( assert ) {
224 var $collapsible = prepareCollapsible(
225 '<div>' + loremIpsum + '</div>',
226 { collapsed: true }
227 );
228
229 assert.assertTrue( $collapsible.hasClass( 'mw-collapsed' ), 'mw-collapsed class present' );
230 } );
231
232 QUnit.test( 'initial collapse (mw-collapsed class)', function ( assert ) {
233 var $collapsible = prepareCollapsible(
234 '<div class="mw-collapsible mw-collapsed">' + loremIpsum + '</div>'
235 ),
236 $content = $collapsible.find( '.mw-collapsible-content' );
237
238 // Synchronous - mw-collapsed should cause instantHide: true to be used on initial collapsing
239 assert.assertTrue( $content.is( ':hidden' ), 'content is hidden' );
240
241 $collapsible.on( 'afterExpand.mw-collapsible', function () {
242 assert.assertTrue( $content.is( ':visible' ), 'after expanding: content is visible' );
243 } );
244
245 $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
246 } );
247
248 QUnit.test( 'initial collapse (options.collapsed)', function ( assert ) {
249 var $collapsible = prepareCollapsible(
250 '<div class="mw-collapsible">' + loremIpsum + '</div>',
251 { collapsed: true }
252 ),
253 $content = $collapsible.find( '.mw-collapsible-content' );
254
255 // Synchronous - collapsed: true should cause instantHide: true to be used on initial collapsing
256 assert.assertTrue( $content.is( ':hidden' ), 'content is hidden' );
257
258 $collapsible.on( 'afterExpand.mw-collapsible', function () {
259 assert.assertTrue( $content.is( ':visible' ), 'after expanding: content is visible' );
260 } );
261
262 $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
263 } );
264
265 QUnit.test( 'clicks on links inside toggler pass through', function ( assert ) {
266 var $collapsible = prepareCollapsible(
267 '<div class="mw-collapsible">' +
268 '<div class="mw-collapsible-toggle">' +
269 'Toggle <a href="#top">toggle</a> toggle <b>toggle</b>' +
270 '</div>' +
271 '<div class="mw-collapsible-content">' + loremIpsum + '</div>' +
272 '</div>',
273 // Can't do asynchronous because we're testing that the event *doesn't* happen
274 { instantHide: true }
275 ),
276 $content = $collapsible.find( '.mw-collapsible-content' );
277
278 $collapsible.find( '.mw-collapsible-toggle a' ).trigger( 'click' );
279 assert.assertTrue( $content.is( ':visible' ), 'click event on link inside toggle passes through (content not toggled)' );
280
281 $collapsible.find( '.mw-collapsible-toggle b' ).trigger( 'click' );
282 assert.assertTrue( $content.is( ':hidden' ), 'click event on non-link inside toggle toggles content' );
283 } );
284
285 QUnit.test( 'click on non-link inside toggler counts as trigger', function ( assert ) {
286 var $collapsible = prepareCollapsible(
287 '<div class="mw-collapsible">' +
288 '<div class="mw-collapsible-toggle">' +
289 'Toggle <a>toggle</a> toggle <b>toggle</b>' +
290 '</div>' +
291 '<div class="mw-collapsible-content">' + loremIpsum + '</div>' +
292 '</div>',
293 { instantHide: true }
294 ),
295 $content = $collapsible.find( '.mw-collapsible-content' );
296
297 $collapsible.find( '.mw-collapsible-toggle a' ).trigger( 'click' );
298 assert.assertTrue( $content.is( ':hidden' ), 'click event on link (with no href) inside toggle toggles content' );
299 } );
300
301 QUnit.test( 'collapse/expand text (data-collapsetext, data-expandtext)', function ( assert ) {
302 var $collapsible = prepareCollapsible(
303 '<div class="mw-collapsible" data-collapsetext="Collapse me!" data-expandtext="Expand me!">' +
304 loremIpsum +
305 '</div>'
306 ),
307 $toggleText = $collapsible.find( '.mw-collapsible-text' );
308
309 assert.strictEqual( $toggleText.text(), 'Collapse me!', 'data-collapsetext is respected' );
310
311 $collapsible.on( 'afterCollapse.mw-collapsible', function () {
312 assert.strictEqual( $toggleText.text(), 'Expand me!', 'data-expandtext is respected' );
313 } );
314
315 $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
316 } );
317
318 QUnit.test( 'collapse/expand text (options.collapseText, options.expandText)', function ( assert ) {
319 var $collapsible = prepareCollapsible(
320 '<div class="mw-collapsible">' + loremIpsum + '</div>',
321 { collapseText: 'Collapse me!', expandText: 'Expand me!' }
322 ),
323 $toggleText = $collapsible.find( '.mw-collapsible-text' );
324
325 assert.strictEqual( $toggleText.text(), 'Collapse me!', 'options.collapseText is respected' );
326
327 $collapsible.on( 'afterCollapse.mw-collapsible', function () {
328 assert.strictEqual( $toggleText.text(), 'Expand me!', 'options.expandText is respected' );
329 } );
330
331 $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
332 } );
333
334 QUnit.test( 'predefined toggle button and text (.mw-collapsible-toggle/.mw-collapsible-text)', function ( assert ) {
335 var $collapsible = prepareCollapsible(
336 '<div class="mw-collapsible">' +
337 '<div class="mw-collapsible-toggle">' +
338 '<span>[</span><span class="mw-collapsible-text">Toggle</span><span>]</span>' +
339 '</div>' +
340 '<div class="mw-collapsible-content">' + loremIpsum + '</div>' +
341 '</div>',
342 { collapseText: 'Hide', expandText: 'Show' }
343 ),
344 $toggleText = $collapsible.find( '.mw-collapsible-text' );
345
346 assert.strictEqual( $toggleText.text(), 'Toggle', 'predefined text remains' );
347
348 $collapsible.on( 'afterCollapse.mw-collapsible', function () {
349 assert.strictEqual( $toggleText.text(), 'Show', 'predefined text is toggled' );
350
351 $collapsible.on( 'afterExpand.mw-collapsible', function () {
352 assert.strictEqual( $toggleText.text(), 'Hide', 'predefined text is toggled back' );
353 } );
354
355 $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
356 } );
357
358 $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
359 } );
360
361 QUnit.test( 'cloned collapsibles can be made collapsible again', function ( assert ) {
362 var $collapsible = prepareCollapsible(
363 '<div class="mw-collapsible">' + loremIpsum + '</div>'
364 ),
365 $clone = $collapsible.clone() // clone without data and events
366 .appendTo( '#qunit-fixture' ).makeCollapsible(),
367 $content = $clone.find( '.mw-collapsible-content' );
368
369 assert.assertTrue( $content.is( ':visible' ), 'content is visible' );
370
371 $clone.on( 'afterCollapse.mw-collapsible', function () {
372 assert.assertTrue( $content.is( ':hidden' ), 'after collapsing: content is hidden' );
373 } );
374
375 $clone.find( '.mw-collapsible-toggle a' ).trigger( 'click' );
376 } );
377
378 QUnit.test( 'T168689 - nested collapsible divs should keep independent state', function ( assert ) {
379 var $collapsible1 = prepareCollapsible(
380 '<div class="mw-collapsible">' + loremIpsum + '</div>'
381 ),
382 $collapsible2 = prepareCollapsible(
383 '<div class="mw-collapsible">' + loremIpsum + '</div>'
384 );
385
386 $collapsible1
387 .append( $collapsible2 )
388 .appendTo( '#qunit-fixture' ).makeCollapsible();
389
390 $collapsible1.on( 'afterCollapse.mw-collapsible', function () {
391 assert.assertTrue( $collapsible1.hasClass( 'mw-collapsed' ), 'after collapsing: parent is collapsed' );
392 assert.assertFalse( $collapsible2.hasClass( 'mw-collapsed' ), 'after collapsing: child is not collapsed' );
393 assert.assertTrue( $collapsible1.find( '> .mw-collapsible-toggle' ).hasClass( 'mw-collapsible-toggle-collapsed' ) );
394 assert.assertFalse( $collapsible2.find( '> .mw-collapsible-toggle' ).hasClass( 'mw-collapsible-toggle-collapsed' ) );
395 } ).find( '> .mw-collapsible-toggle a' ).trigger( 'click' );
396 } );
397 }() );