summaryrefslogtreecommitdiff
path: root/tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js
blob: 804058193bf99d9233b3ae16f185724cb270cc91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
( function ( mw, $ ) {
	var loremIpsum = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.';

	QUnit.module( 'jquery.makeCollapsible', QUnit.newMwEnvironment( {
		setup: function () {
			this.clock = this.sandbox.useFakeTimers();
		}
	} ) );

	function prepareCollapsible( html, options ) {
		return $( $.parseHTML( html ) )
			.appendTo( '#qunit-fixture' )
			// options might be undefined here - this is okay
			.makeCollapsible( options );
	}

	// This test is first because if it fails, then almost all of the latter tests are meaningless.
	QUnit.test( 'testing hooks/triggers', 4, function ( assert ) {
		var test = this,
			$collapsible = prepareCollapsible(
				'<div class="mw-collapsible">' + loremIpsum + '</div>'
			),
			$content = $collapsible.find( '.mw-collapsible-content' ),
			$toggle = $collapsible.find( '.mw-collapsible-toggle' );

		// In one full collapse-expand cycle, each event will be fired once

		// On collapse...
		$collapsible.on( 'beforeCollapse.mw-collapsible', function () {
			assert.assertTrue( $content.is( ':visible' ), 'first beforeCollapseExpand: content is visible' );
		} );
		$collapsible.on( 'afterCollapse.mw-collapsible', function () {
			assert.assertTrue( $content.is( ':hidden' ), 'first afterCollapseExpand: content is hidden' );

			// On expand...
			$collapsible.on( 'beforeExpand.mw-collapsible', function () {
				assert.assertTrue( $content.is( ':hidden' ), 'second beforeCollapseExpand: content is hidden' );
			} );
			$collapsible.on( 'afterExpand.mw-collapsible', function () {
				assert.assertTrue( $content.is( ':visible' ), 'second afterCollapseExpand: content is visible' );
			} );

			// ...expanding happens here
			$toggle.trigger( 'click' );
			test.clock.tick( 500 );
		} );

		// ...collapsing happens here
		$toggle.trigger( 'click' );
		test.clock.tick( 500 );
	} );

	QUnit.test( 'basic operation (<div>)', 5, function ( assert ) {
		var test = this,
			$collapsible = prepareCollapsible(
				'<div class="mw-collapsible">' + loremIpsum + '</div>'
			),
			$content = $collapsible.find( '.mw-collapsible-content' ),
			$toggle = $collapsible.find( '.mw-collapsible-toggle' );

		assert.equal( $content.length, 1, 'content is present' );
		assert.equal( $content.find( $toggle ).length, 0, 'toggle is not a descendant of content' );

		assert.assertTrue( $content.is( ':visible' ), 'content is visible' );

		$collapsible.on( 'afterCollapse.mw-collapsible', function () {
			assert.assertTrue( $content.is( ':hidden' ), 'after collapsing: content is hidden' );

			$collapsible.on( 'afterExpand.mw-collapsible', function () {
				assert.assertTrue( $content.is( ':visible' ), 'after expanding: content is visible' );
			} );

			$toggle.trigger( 'click' );
			test.clock.tick( 500 );
		} );

		$toggle.trigger( 'click' );
		test.clock.tick( 500 );
	} );

	QUnit.test( 'basic operation (<table>)', 7, function ( assert ) {
		var test = this,
			$collapsible = prepareCollapsible(
				'<table class="mw-collapsible">' +
					'<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
					'<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
					'<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
				'</table>'
			),
			$headerRow = $collapsible.find( 'tr:first' ),
			$contentRow = $collapsible.find( 'tr:last' ),
			$toggle = $headerRow.find( 'td:last .mw-collapsible-toggle' );

		assert.equal( $toggle.length, 1, 'toggle is added to last cell of first row' );

		assert.assertTrue( $headerRow.is( ':visible' ), 'headerRow is visible' );
		assert.assertTrue( $contentRow.is( ':visible' ), 'contentRow is visible' );

		$collapsible.on( 'afterCollapse.mw-collapsible', function () {
			assert.assertTrue( $headerRow.is( ':visible' ), 'after collapsing: headerRow is still visible' );
			assert.assertTrue( $contentRow.is( ':hidden' ), 'after collapsing: contentRow is hidden' );

			$collapsible.on( 'afterExpand.mw-collapsible', function () {
				assert.assertTrue( $headerRow.is( ':visible' ), 'after expanding: headerRow is still visible' );
				assert.assertTrue( $contentRow.is( ':visible' ), 'after expanding: contentRow is visible' );
			} );

			$toggle.trigger( 'click' );
			test.clock.tick( 500 );
		} );

		$toggle.trigger( 'click' );
		test.clock.tick( 500 );
	} );

	function tableWithCaptionTest( $collapsible, test, assert ) {
		var $caption = $collapsible.find( 'caption' ),
			$headerRow = $collapsible.find( 'tr:first' ),
			$contentRow = $collapsible.find( 'tr:last' ),
			$toggle = $caption.find( '.mw-collapsible-toggle' );

		assert.equal( $toggle.length, 1, 'toggle is added to the end of the caption' );

		assert.assertTrue( $caption.is( ':visible' ), 'caption is visible' );
		assert.assertTrue( $headerRow.is( ':visible' ), 'headerRow is visible' );
		assert.assertTrue( $contentRow.is( ':visible' ), 'contentRow is visible' );

		$collapsible.on( 'afterCollapse.mw-collapsible', function () {
			assert.assertTrue( $caption.is( ':visible' ), 'after collapsing: caption is still visible' );
			assert.assertTrue( $headerRow.is( ':hidden' ), 'after collapsing: headerRow is hidden' );
			assert.assertTrue( $contentRow.is( ':hidden' ), 'after collapsing: contentRow is hidden' );

			$collapsible.on( 'afterExpand.mw-collapsible', function () {
				assert.assertTrue( $caption.is( ':visible' ), 'after expanding: caption is still visible' );
				assert.assertTrue( $headerRow.is( ':visible' ), 'after expanding: headerRow is visible' );
				assert.assertTrue( $contentRow.is( ':visible' ), 'after expanding: contentRow is visible' );
			} );

			$toggle.trigger( 'click' );
			test.clock.tick( 500 );
		} );

		$toggle.trigger( 'click' );
		test.clock.tick( 500 );
	}

	QUnit.test( 'basic operation (<table> with caption)', 10, function ( assert ) {
		tableWithCaptionTest( prepareCollapsible(
			'<table class="mw-collapsible">' +
				'<caption>' + loremIpsum + '</caption>' +
				'<tr><th>' + loremIpsum + '</th><th>' + loremIpsum + '</th></tr>' +
				'<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
				'<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
			'</table>'
		), this, assert );
	} );

	QUnit.test( 'basic operation (<table> with caption and <thead>)', 10, function ( assert ) {
		tableWithCaptionTest( prepareCollapsible(
			'<table class="mw-collapsible">' +
				'<caption>' + loremIpsum + '</caption>' +
				'<thead><tr><th>' + loremIpsum + '</th><th>' + loremIpsum + '</th></tr></thead>' +
				'<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
				'<tr><td>' + loremIpsum + '</td><td>' + loremIpsum + '</td></tr>' +
			'</table>'
		), this, assert );
	} );

	function listTest( listType, test, assert ) {
		var $collapsible = prepareCollapsible(
				'<' + listType + ' class="mw-collapsible">' +
					'<li>' + loremIpsum + '</li>' +
					'<li>' + loremIpsum + '</li>' +
				'</' + listType + '>'
			),
			$toggleItem = $collapsible.find( 'li.mw-collapsible-toggle-li:first-child' ),
			$contentItem = $collapsible.find( 'li:last' ),
			$toggle = $toggleItem.find( '.mw-collapsible-toggle' );

		assert.equal( $toggle.length, 1, 'toggle is present, added inside new zeroth list item' );

		assert.assertTrue( $toggleItem.is( ':visible' ), 'toggleItem is visible' );
		assert.assertTrue( $contentItem.is( ':visible' ), 'contentItem is visible' );

		$collapsible.on( 'afterCollapse.mw-collapsible', function () {
			assert.assertTrue( $toggleItem.is( ':visible' ), 'after collapsing: toggleItem is still visible' );
			assert.assertTrue( $contentItem.is( ':hidden' ), 'after collapsing: contentItem is hidden' );

			$collapsible.on( 'afterExpand.mw-collapsible', function () {
				assert.assertTrue( $toggleItem.is( ':visible' ), 'after expanding: toggleItem is still visible' );
				assert.assertTrue( $contentItem.is( ':visible' ), 'after expanding: contentItem is visible' );
			} );

			$toggle.trigger( 'click' );
			test.clock.tick( 500 );
		} );

		$toggle.trigger( 'click' );
		test.clock.tick( 500 );
	}

	QUnit.test( 'basic operation (<ul>)', 7, function ( assert ) {
		listTest( 'ul', this, assert );
	} );

	QUnit.test( 'basic operation (<ol>)', 7, function ( assert ) {
		listTest( 'ol', this, assert );
	} );

	QUnit.test( 'basic operation when synchronous (options.instantHide)', 2, function ( assert ) {
		var $collapsible = prepareCollapsible(
				'<div class="mw-collapsible">' + loremIpsum + '</div>',
				{ instantHide: true }
			),
			$content = $collapsible.find( '.mw-collapsible-content' );

		assert.assertTrue( $content.is( ':visible' ), 'content is visible' );

		$collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );

		assert.assertTrue( $content.is( ':hidden' ), 'after collapsing: content is hidden' );
	} );

	QUnit.test( 'mw-made-collapsible data added', 1, function ( assert ) {
		var $collapsible = prepareCollapsible(
				'<div>' + loremIpsum + '</div>'
			);

		assert.equal( $collapsible.data( 'mw-made-collapsible' ), true, 'mw-made-collapsible data present' );
	} );

	QUnit.test( 'mw-collapsible added when missing', 1, function ( assert ) {
		var $collapsible = prepareCollapsible(
				'<div>' + loremIpsum + '</div>'
			);

		assert.assertTrue( $collapsible.hasClass( 'mw-collapsible' ), 'mw-collapsible class present' );
	} );

	QUnit.test( 'mw-collapsed added when missing', 1, function ( assert ) {
		var $collapsible = prepareCollapsible(
			'<div>' + loremIpsum + '</div>',
				{ collapsed: true }
			);

		assert.assertTrue( $collapsible.hasClass( 'mw-collapsed' ), 'mw-collapsed class present' );
	} );

	QUnit.test( 'initial collapse (mw-collapsed class)', 2, function ( assert ) {
		var $collapsible = prepareCollapsible(
				'<div class="mw-collapsible mw-collapsed">' + loremIpsum + '</div>'
			),
			$content = $collapsible.find( '.mw-collapsible-content' );

		// Synchronous - mw-collapsed should cause instantHide: true to be used on initial collapsing
		assert.assertTrue( $content.is( ':hidden' ), 'content is hidden' );

		$collapsible.on( 'afterExpand.mw-collapsible', function () {
			assert.assertTrue( $content.is( ':visible' ), 'after expanding: content is visible' );
		} );

		$collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
		this.clock.tick( 500 );
	} );

	QUnit.test( 'initial collapse (options.collapsed)', 2, function ( assert ) {
		var $collapsible = prepareCollapsible(
				'<div class="mw-collapsible">' + loremIpsum + '</div>',
				{ collapsed: true }
			),
			$content = $collapsible.find( '.mw-collapsible-content' );

		// Synchronous - collapsed: true should cause instantHide: true to be used on initial collapsing
		assert.assertTrue( $content.is( ':hidden' ), 'content is hidden' );

		$collapsible.on( 'afterExpand.mw-collapsible', function () {
			assert.assertTrue( $content.is( ':visible' ), 'after expanding: content is visible' );
		} );

		$collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
		this.clock.tick( 500 );
	} );

	QUnit.test( 'clicks on links inside toggler pass through (options.linksPassthru)', 2, function ( assert ) {
		var $collapsible = prepareCollapsible(
				'<div class="mw-collapsible">' +
					'<div class="mw-collapsible-toggle">' +
						'Toggle <a href="#top">toggle</a> toggle <b>toggle</b>' +
					'</div>' +
					'<div class="mw-collapsible-content">' + loremIpsum + '</div>' +
				'</div>',
				// Can't do asynchronous because we're testing that the event *doesn't* happen
				{ instantHide: true }
			),
			$content = $collapsible.find( '.mw-collapsible-content' );

		$collapsible.find( '.mw-collapsible-toggle a' ).trigger( 'click' );
		assert.assertTrue( $content.is( ':visible' ), 'click event on link inside toggle passes through (content not toggled)' );

		$collapsible.find( '.mw-collapsible-toggle b' ).trigger( 'click' );
		assert.assertTrue( $content.is( ':hidden' ), 'click event on non-link inside toggle toggles content' );
	} );

	QUnit.test( 'collapse/expand text (data-collapsetext, data-expandtext)', 2, function ( assert ) {
		var $collapsible = prepareCollapsible(
				'<div class="mw-collapsible" data-collapsetext="Collapse me!" data-expandtext="Expand me!">' +
					loremIpsum +
				'</div>'
			),
			$toggleLink = $collapsible.find( '.mw-collapsible-toggle a' );

		assert.equal( $toggleLink.text(), 'Collapse me!', 'data-collapsetext is respected' );

		$collapsible.on( 'afterCollapse.mw-collapsible', function () {
			assert.equal( $toggleLink.text(), 'Expand me!', 'data-expandtext is respected' );
		} );

		$collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
		this.clock.tick( 500 );
	} );

	QUnit.test( 'collapse/expand text (options.collapseText, options.expandText)', 2, function ( assert ) {
		var $collapsible = prepareCollapsible(
				'<div class="mw-collapsible">' + loremIpsum + '</div>',
				{ collapseText: 'Collapse me!', expandText: 'Expand me!' }
			),
			$toggleLink = $collapsible.find( '.mw-collapsible-toggle a' );

		assert.equal( $toggleLink.text(), 'Collapse me!', 'options.collapseText is respected' );

		$collapsible.on( 'afterCollapse.mw-collapsible', function () {
			assert.equal( $toggleLink.text(), 'Expand me!', 'options.expandText is respected' );
		} );

		$collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' );
		this.clock.tick( 500 );
	} );

}( mediaWiki, jQuery ) );