2 * mobile listview unit tests
5 // TODO split out into seperate test files
7 var home = $.mobile.path.parseUrl( location.href ).pathname;
9 $.mobile.defaultTransition = "none";
11 module( "Basic Linked list", {
13 $.testHelper.openPage( "#basic-linked-test" );
17 asyncTest( "The page should enhanced correctly", function(){
18 setTimeout(function() {
19 ok($('#basic-linked-test .ui-li').length, ".ui-li classes added to li elements");
24 asyncTest( "Slides to the listview page when the li a is clicked", function() {
25 $.testHelper.pageSequence([
27 $.testHelper.openPage("#basic-linked-test");
31 $('#basic-linked-test li a').first().click();
35 ok($('#basic-link-results').hasClass('ui-page-active'));
41 asyncTest( "Slides back to main page when back button is clicked", function() {
42 $.testHelper.pageSequence([
44 $.testHelper.openPage("#basic-link-results");
48 window.history.back();
52 ok($('#basic-linked-test').hasClass('ui-page-active'));
58 asyncTest( "Presence of ui-li-has- classes", function(){
59 $.testHelper.pageSequence( [
61 $.testHelper.openPage( "#ui-li-has-test" );
65 var page = $( ".ui-page-active" ),
66 items = page.find( "li" );
68 ok( items.eq( 0 ).hasClass( "ui-li-has-count"), "First LI should have ui-li-has-count class" );
69 ok( items.eq( 0 ).hasClass( "ui-li-has-arrow"), "First LI should have ui-li-has-arrow class" );
70 ok( !items.eq( 1 ).hasClass( "ui-li-has-count"), "Second LI should NOT have ui-li-has-count class" );
71 ok( items.eq( 1 ).hasClass( "ui-li-has-arrow"), "Second LI should have ui-li-has-arrow class" );
72 ok( !items.eq( 2 ).hasClass( "ui-li-has-count"), "Third LI should NOT have ui-li-has-count class" );
73 ok( !items.eq( 2 ).hasClass( "ui-li-has-arrow"), "Third LI should NOT have ui-li-has-arrow class" );
74 ok( items.eq( 3 ).hasClass( "ui-li-has-count"), "Fourth LI should have ui-li-has-count class" );
75 ok( !items.eq( 3 ).hasClass( "ui-li-has-arrow"), "Fourth LI should NOT have ui-li-has-arrow class" );
76 ok( !items.eq( 4 ).hasClass( "ui-li-has-count"), "Fifth LI should NOT have ui-li-has-count class" );
77 ok( !items.eq( 4 ).hasClass( "ui-li-has-arrow"), "Fifth LI should NOT have ui-li-has-arrow class" );
83 module('Nested List Test');
85 asyncTest( "Changes page to nested list test and enhances", function() {
86 $.testHelper.pageSequence([
88 $.testHelper.openPage("#nested-list-test");
92 ok($('#nested-list-test').hasClass('ui-page-active'), "makes nested list test page active");
93 ok($(':jqmData(url="nested-list-test&ui-page=0-0")').length == 1, "Adds first UL to the page");
94 ok($(':jqmData(url="nested-list-test&ui-page=0-1")').length == 1, "Adds second nested UL to the page");
100 asyncTest( "change to nested page when the li a is clicked", function() {
102 $.testHelper.pageSequence([
104 $.testHelper.openPage("#nested-list-test");
108 $('.ui-page-active li:eq(1) a:eq(0)').click();
112 var $new_page = $(':jqmData(url="nested-list-test&ui-page=0-0")');
114 ok($new_page.hasClass('ui-page-active'), 'Makes the nested page the active page.');
115 ok($('.ui-listview', $new_page).find(":contains('Rhumba of rattlesnakes')").length == 1, "The current page should have the proper text in the list.");
116 ok($('.ui-listview', $new_page).find(":contains('Shoal of Bass')").length == 1, "The current page should have the proper text in the list.");
122 asyncTest( "should go back to top level when the back button is clicked", function() {
123 $.testHelper.pageSequence([
125 $.testHelper.openPage("#nested-list-test&ui-page=0-0");
129 window.history.back();
133 ok($('#nested-list-test').hasClass('ui-page-active'), 'Transitions back to the parent nested page');
139 test( "nested list title should use first text node, regardless of line breaks", function(){
140 ok($('#nested-list-test .linebreaknode').text() === "More animals", 'Text should be "More animals"');
143 asyncTest( "Multiple nested lists on a page with same labels", function() {
144 $.testHelper.pageSequence([
146 // https://github.com/jquery/jquery-mobile/issues/1617
147 $.testHelper.openPage("#nested-lists-test");
151 // Click on the link of the third li element
152 $('.ui-page-active li:eq(2) a:eq(0)').click();
156 equal($('.ui-page-active .ui-content .ui-listview li').text(), "Item A-3-0Item A-3-1Item A-3-2", 'Text should be "Item A-3-0Item A-3-1Item A-3-2"');
162 module('Ordered Lists');
164 asyncTest( "changes to the numbered list page and enhances it", function() {
165 $.testHelper.pageSequence([
167 $.testHelper.openPage("#numbered-list-test");
171 var $new_page = $('#numbered-list-test');
172 ok($new_page.hasClass('ui-page-active'), "Makes the new page active when the hash is changed.");
173 ok($('.ui-link-inherit', $new_page).first().text() == "Number 1", "The text of the first LI should be Number 1");
179 asyncTest( "changes to number 1 page when the li a is clicked", function() {
180 $.testHelper.pageSequence([
182 $('#numbered-list-test li a').first().click();
186 ok($('#numbered-list-results').hasClass('ui-page-active'), "The new numbered page was transitioned correctly.");
192 asyncTest( "takes us back to the numbered list when the back button is clicked", function() {
193 $.testHelper.pageSequence([
195 $.testHelper.openPage('#numbered-list-test');
199 $.testHelper.openPage('#numbered-list-results');
203 window.history.back();
207 ok($('#numbered-list-test').hasClass('ui-page-active'));
213 module('Read only list');
215 asyncTest( "changes to the read only page when hash is changed", function() {
216 $.testHelper.pageSequence([
218 $.testHelper.openPage("#read-only-list-test");
222 var $new_page = $('#read-only-list-test');
223 ok($new_page.hasClass('ui-page-active'), "makes the read only page the active page");
224 ok($('li', $new_page).first().text() === "Read", "The first LI has the proper text.");
230 module('Split view list');
232 asyncTest( "changes the page to the split view list and enhances it correctly.", function() {
233 $.testHelper.pageSequence([
235 $.testHelper.openPage("#split-list-test");
239 var $new_page = $('#split-list-test');
240 ok($('.ui-li-link-alt', $new_page).length == 3);
241 ok($('.ui-link-inherit', $new_page).length == 3);
247 asyncTest( "change the page to the split view page 1 when the first link is clicked", function() {
248 $.testHelper.pageSequence([
250 $.testHelper.openPage("#split-list-test");
254 $('.ui-page-active .ui-li a:eq(0)').click();
258 ok($('#split-list-link1').hasClass('ui-page-active'));
264 asyncTest( "Slide back to the parent list view when the back button is clicked", function() {
265 $.testHelper.pageSequence([
267 $.testHelper.openPage("#split-list-test");
271 $('.ui-page-active .ui-listview a:eq(0)').click();
279 ok($('#split-list-test').hasClass('ui-page-active'));
285 asyncTest( "Clicking on the icon (the second link) should take the user to other a href of this LI", function() {
286 $.testHelper.pageSequence([
288 $.testHelper.openPage("#split-list-test");
292 $('.ui-page-active .ui-li-link-alt:eq(0)').click();
296 ok($('#split-list-link2').hasClass('ui-page-active'));
302 module( "List Dividers" );
304 asyncTest( "Makes the list divider page the active page and enhances it correctly.", function() {
305 $.testHelper.pageSequence([
307 $.testHelper.openPage("#list-divider-test");
311 var $new_page = $('#list-divider-test');
312 ok($new_page.find('.ui-li-divider').length == 2);
313 ok($new_page.hasClass('ui-page-active'));
319 module( "Search Filter");
321 var searchFilterId = "#search-filter-test";
324 asyncTest( "Filter downs results when the user enters information", function() {
325 var $searchPage = $(searchFilterId);
326 $.testHelper.pageSequence([
328 $.testHelper.openPage(searchFilterId);
332 $searchPage.find('input').val('at');
333 $searchPage.find('input').trigger('change');
335 same($searchPage.find('li.ui-screen-hidden').length, 2);
341 asyncTest( "Redisplay results when user removes values", function() {
342 var $searchPage = $(searchFilterId);
343 $.testHelper.pageSequence([
345 $.testHelper.openPage(searchFilterId);
349 $searchPage.find('input').val('a');
350 $searchPage.find('input').trigger('change');
352 same($searchPage.find("li[style^='display: none;']").length, 0);
358 asyncTest( "Filter works fine with \\W- or regexp-special-characters", function() {
359 var $searchPage = $(searchFilterId);
360 $.testHelper.pageSequence([
362 $.testHelper.openPage(searchFilterId);
366 $searchPage.find('input').val('*');
367 $searchPage.find('input').trigger('change');
369 same($searchPage.find('li.ui-screen-hidden').length, 4);
375 test( "Refresh applies thumb styling", function(){
376 var ul = $('.ui-page-active ul');
378 ul.append("<li id='fiz'><img/></li>");
379 ok(!ul.find("#fiz img").hasClass("ui-li-thumb"));
380 ul.listview('refresh');
381 ok(ul.find("#fiz img").hasClass("ui-li-thumb"));
384 asyncTest( "Filter downs results and dividers when the user enters information", function() {
385 var $searchPage = $("#search-filter-with-dividers-test");
386 $.testHelper.pageSequence([
388 $.testHelper.openPage("#search-filter-with-dividers-test");
391 // wait for the page to become active/enhanced
393 $searchPage.find('input').val('at');
394 $searchPage.find('input').trigger('change');
395 setTimeout(function() {
396 //there should be four hidden list entries
397 same($searchPage.find('li.ui-screen-hidden').length, 4);
399 //there should be two list entries that are list dividers and hidden
400 same($searchPage.find('li.ui-screen-hidden:jqmData(role=list-divider)').length, 2);
402 //there should be two list entries that are not list dividers and hidden
403 same($searchPage.find('li.ui-screen-hidden:not(:jqmData(role=list-divider))').length, 2);
410 asyncTest( "Redisplay results when user removes values", function() {
411 $.testHelper.pageSequence([
413 $.testHelper.openPage("#search-filter-with-dividers-test");
417 $('.ui-page-active input').val('a');
418 $('.ui-page-active input').trigger('change');
420 setTimeout(function() {
421 same($('.ui-page-active input').val(), 'a');
422 same($('.ui-page-active li[style^="display: none;"]').length, 0);
429 asyncTest( "Dividers are hidden when preceding hidden rows and shown when preceding shown rows", function () {
430 $.testHelper.pageSequence([
432 $.testHelper.openPage("#search-filter-with-dividers-test");
436 var $page = $('.ui-page-active');
438 $page.find('input').val('at');
439 $page.find('input').trigger('change');
441 setTimeout(function() {
442 same($page.find('li:jqmData(role=list-divider):hidden').length, 2);
443 same($page.find('li:jqmData(role=list-divider):hidden + li:not(:jqmData(role=list-divider)):hidden').length, 2);
444 same($page.find('li:jqmData(role=list-divider):not(:hidden) + li:not(:jqmData(role=list-divider)):not([:hidden)').length, 2);
451 asyncTest( "Inset List View should refresh corner classes after filtering", 4 * 2, function () {
452 var checkClasses = function() {
453 var $page = $( ".ui-page-active" ),
454 $li = $page.find( "li:visible" );
455 ok($li.first().hasClass( "ui-corner-top" ), $li.length+" li elements: First visible element should have class ui-corner-top");
456 ok($li.last().hasClass( "ui-corner-bottom" ), $li.length+" li elements: Last visible element should have class ui-corner-bottom");
459 $.testHelper.pageSequence([
461 $.testHelper.openPage("#search-filter-inset-test");
465 var $page = $('.ui-page-active');
466 $.testHelper.sequence([
470 $page.find('input').val('man');
471 $page.find('input').trigger('change');
477 $page.find('input').val('at');
478 $page.find('input').trigger('change');
484 $page.find('input').val('catwoman');
485 $page.find('input').trigger('change');
497 module( "Programmatically generated list items", {
519 $( "#programmatically-generated-list-items" ).html("");
521 for ( var i = 0, len = data.length; i < len; i++ ) {
522 item = $( '<li id="myItem' + data[i].id + '">' );
523 label = $( "<strong>" + data[i].label + "</strong>").appendTo( item );
524 $( "#programmatically-generated-list-items" ).append( item );
529 asyncTest( "Corner styling on programmatically created list items", function() {
530 // https://github.com/jquery/jquery-mobile/issues/1470
531 $.testHelper.pageSequence([
533 $.testHelper.openPage( "#programmatically-generated-list" );
536 ok(!$( "#programmatically-generated-list-items li:first-child" ).hasClass( "ui-corner-bottom" ), "First list item should not have class ui-corner-bottom" );
542 module("Programmatic list items manipulation");
544 asyncTest("Removing list items", 4, function() {
545 $.testHelper.pageSequence([
547 $.testHelper.openPage("#removing-items-from-list-test");
551 var ul = $('#removing-items-from-list-test ul');
552 ul.find("li").first().remove();
553 equal(ul.find("li").length, 3, "There should be only 3 list items left");
555 ul.listview('refresh');
556 ok(ul.find("li").first().hasClass("ui-corner-top"), "First list item should have class ui-corner-top");
558 ul.find("li").last().remove();
559 equal(ul.find("li").length, 2, "There should be only 2 list items left");
561 ul.listview('refresh');
562 ok(ul.find("li").last().hasClass("ui-corner-bottom"), "Last list item should have class ui-corner-bottom");
568 module("Rounded corners");
570 asyncTest("Top and bottom corners rounded in inset list", 14, function() {
571 $.testHelper.pageSequence([
573 $.testHelper.openPage("#corner-rounded-test");
577 var ul = $('#corner-rounded-test ul');
579 for( var t = 0; t<3; t++){
580 ul.append("<li>Item " + t + "</li>");
581 ul.listview('refresh');
582 equals(ul.find(".ui-corner-top").length, 1, "There should be only one element with class ui-corner-top");
583 equals(ul.find("li:visible").first()[0], ul.find(".ui-corner-top")[0], "First list item should have class ui-corner-top in list with " + ul.find("li").length + " item(s)");
584 equals(ul.find(".ui-corner-bottom").length, 1, "There should be only one element with class ui-corner-bottom");
585 equals(ul.find("li:visible").last()[0], ul.find(".ui-corner-bottom")[0], "Last list item should have class ui-corner-bottom in list with " + ul.find("li").length + " item(s)");
588 ul.find( "li" ).first().hide();
589 ul.listview( "refresh" );
590 equals(ul.find("li:visible").first()[0], ul.find(".ui-corner-top")[0], "First visible list item should have class ui-corner-top");
592 ul.find( "li" ).last().hide();
593 ul.listview( "refresh" );
594 equals(ul.find("li:visible").last()[0], ul.find(".ui-corner-bottom")[0], "Last visible list item should have class ui-corner-bottom");
601 test( "Listview will create when inside a container that receives a 'create' event", function(){
602 ok( !$("#enhancetest").appendTo(".ui-page-active").find(".ui-listview").length, "did not have enhancements applied" );
603 ok( $("#enhancetest").trigger("create").find(".ui-listview").length, "enhancements applied" );
606 module( "Cached Linked List" );
608 var findNestedPages = function(selector){
609 return $( selector + " #topmost" ).listview( 'childPages' );
612 asyncTest( "nested pages are removed from the dom by default", function(){
613 $.testHelper.pageSequence([
615 //reset for relative url refs
616 $.testHelper.openPage( "#" + home );
620 $.testHelper.openPage( "#cache-tests/uncached-nested.html" );
624 ok( findNestedPages( "#uncached-nested-list" ).length > 0, "verify that there are nested pages" );
625 $.testHelper.openPage( "#" + home );
629 $.testHelper.openPage( "#cache-tests/clear.html" );
633 same( findNestedPages( "#uncached-nested-list" ).length, 0 );
639 asyncTest( "nested pages preserved when parent page is cached", function(){
641 $.testHelper.pageSequence([
643 //reset for relative url refs
644 $.testHelper.openPage( "#" + home );
648 $.testHelper.openPage( "#cache-tests/cached-nested.html" );
652 ok( findNestedPages( "#cached-nested-list" ).length > 0, "verify that there are nested pages" );
653 $.testHelper.openPage( "#" + home );
657 $.testHelper.openPage( "#cache-tests/clear.html" );
661 ok( findNestedPages( "#cached-nested-list" ).length > 0, "nested pages remain" );
667 asyncTest( "parent page is not removed when visiting a sub page", function(){
668 $.testHelper.pageSequence([
670 //reset for relative url refs
671 $.testHelper.openPage( "#" + home );
675 $.testHelper.openPage( "#cache-tests/cached-nested.html" );
679 same( $("#cached-nested-list").length, 1 );
680 $.testHelper.openPage( "#" + home );
684 $.testHelper.openPage( "#cache-tests/clear.html" );
688 same( $("#cached-nested-list").length, 1 );
694 asyncTest( "filterCallback can be altered after widget creation", function(){
695 var listPage = $( "#search-filter-test" );
696 expect( listPage.find("li").length );
698 $.testHelper.pageSequence( [
700 //reset for relative url refs
701 $.testHelper.openPage( "#" + home );
705 $.testHelper.openPage( "#search-filter-test" );
709 // set the listview instance callback
710 listPage.find( "ul" ).listview( "option", "filterCallback", function() {
711 ok(true, "custom callback invoked");
714 // trigger a change in the search filter
715 listPage.find( "input" ).val( "foo" ).trigger( "change" );
717 //NOTE beware a poossible issue with timing here
723 asyncTest( "nested pages hash key is always in the hash (replaceState)", function(){
724 $.testHelper.pageSequence([
726 //reset for relative url refs
727 $.testHelper.openPage( "#" + home );
731 // https://github.com/jquery/jquery-mobile/issues/1617
732 $.testHelper.openPage("#nested-lists-test");
736 // Click on the link of the third li element
737 $('.ui-page-active li:eq(2) a:eq(0)').click();
741 ok( location.hash.search($.mobile.subPageUrlKey) >= 0 );
747 asyncTest( "embedded listview page with nested pages is not removed from the dom", function() {
748 $.testHelper.pageSequence([
750 // open the nested list page
751 same( $("div#nested-list-test").length, 1 );
752 $( "a#nested-list-test-anchor" ).click();
756 // go back to the origin page
757 window.history.back();
761 // make sure the page is still in place
762 same( $("div#nested-list-test").length, 1 );
769 asyncTest( "list inherits theme from parent", function() {
770 $.testHelper.pageSequence([
772 $.testHelper.openPage("#list-theme-inherit");
776 var theme = $.mobile.activePage.jqmData('theme');
777 ok( $.mobile.activePage.find("ul > li").hasClass("ui-body-b"), "theme matches the parent");
778 window.history.back();