@@ -678,3 +678,149 @@ test('9. Routing > should allow me to display active/completed/all items',
678678 t . end ( ) ;
679679} ) ;
680680
681+ test ( '10. Search > should filter todos by search term' , function ( t ) {
682+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
683+ elmish . empty ( document . getElementById ( id ) ) ;
684+ const model = {
685+ todos : [
686+ { id : 0 , title : "Buy milk" , done : false } ,
687+ { id : 1 , title : "Buy eggs" , done : false } ,
688+ { id : 2 , title : "Walk the dog" , done : true }
689+ ] ,
690+ hash : '#/'
691+ } ;
692+ elmish . mount ( model , app . update , app . view , id , app . subscriptions ) ;
693+
694+ t . equal ( document . querySelectorAll ( '.view' ) . length , 3 , "three items total" ) ;
695+
696+ const model_with_search = app . update ( 'SEARCH' , model , 'milk' ) ;
697+ elmish . empty ( document . getElementById ( id ) ) ;
698+ document . getElementById ( id ) . appendChild ( app . render_main ( model_with_search , mock_signal ) ) ;
699+
700+ t . equal ( document . querySelectorAll ( '.view' ) . length , 1 , "one item matches 'milk'" ) ;
701+ t . equal ( document . querySelectorAll ( '.view' ) [ 0 ] . textContent , 'Buy milk' , "matching item is 'Buy milk'" ) ;
702+
703+ elmish . empty ( document . getElementById ( id ) ) ;
704+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
705+ t . end ( ) ;
706+ } ) ;
707+
708+ test ( '10.1 Search > should ignore leading and trailing whitespace in search term' , function ( t ) {
709+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
710+ elmish . empty ( document . getElementById ( id ) ) ;
711+ const model = {
712+ todos : [
713+ { id : 0 , title : "Buy milk" , done : false } ,
714+ { id : 1 , title : "Buy eggs" , done : false }
715+ ] ,
716+ hash : '#/'
717+ } ;
718+
719+ const model_with_whitespace = app . update ( 'SEARCH' , model , ' milk ' ) ;
720+ document . getElementById ( id ) . appendChild ( app . render_main ( model_with_whitespace , mock_signal ) ) ;
721+
722+ t . equal ( document . querySelectorAll ( '.view' ) . length , 1 , "one item matches ' milk ' (trimmed)" ) ;
723+ t . equal ( document . querySelectorAll ( '.view' ) [ 0 ] . textContent , 'Buy milk' , "matching item is 'Buy milk'" ) ;
724+
725+ elmish . empty ( document . getElementById ( id ) ) ;
726+
727+ const model_with_only_spaces = app . update ( 'SEARCH' , model , ' ' ) ;
728+ document . getElementById ( id ) . appendChild ( app . render_main ( model_with_only_spaces , mock_signal ) ) ;
729+
730+ t . equal ( document . querySelectorAll ( '.view' ) . length , 2 , "all items shown when search term is only spaces" ) ;
731+
732+ elmish . empty ( document . getElementById ( id ) ) ;
733+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
734+ t . end ( ) ;
735+ } ) ;
736+
737+ test ( '10.2 Search > should show empty message when no items match search' , function ( t ) {
738+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
739+ elmish . empty ( document . getElementById ( id ) ) ;
740+ const model = {
741+ todos : [
742+ { id : 0 , title : "Buy milk" , done : false } ,
743+ { id : 1 , title : "Buy eggs" , done : false }
744+ ] ,
745+ hash : '#/'
746+ } ;
747+
748+ const model_with_search = app . update ( 'SEARCH' , model , 'nonexistent' ) ;
749+ document . getElementById ( id ) . appendChild ( app . render_main ( model_with_search , mock_signal ) ) ;
750+
751+ t . equal ( document . querySelectorAll ( '.view' ) . length , 0 , "no items match 'nonexistent'" ) ;
752+ t . equal ( document . querySelectorAll ( '.empty-message' ) . length , 1 , "empty message is shown" ) ;
753+ t . equal ( document . querySelectorAll ( '.empty-message' ) [ 0 ] . textContent , 'No todos match your search.' , "empty message text is correct" ) ;
754+
755+ elmish . empty ( document . getElementById ( id ) ) ;
756+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
757+ t . end ( ) ;
758+ } ) ;
759+
760+ test ( '10.3 Search > should not show empty message when there are no todos at all' , function ( t ) {
761+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
762+ elmish . empty ( document . getElementById ( id ) ) ;
763+ const model = {
764+ todos : [ ] ,
765+ hash : '#/'
766+ } ;
767+
768+ const model_with_search = app . update ( 'SEARCH' , model , 'milk' ) ;
769+ document . getElementById ( id ) . appendChild ( app . render_main ( model_with_search , mock_signal ) ) ;
770+
771+ t . equal ( document . querySelectorAll ( '.empty-message' ) . length , 0 , "no empty message when there are no todos" ) ;
772+
773+ elmish . empty ( document . getElementById ( id ) ) ;
774+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
775+ t . end ( ) ;
776+ } ) ;
777+
778+ test ( '10.4 Search > should combine with route filter' , function ( t ) {
779+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
780+ elmish . empty ( document . getElementById ( id ) ) ;
781+ const model = {
782+ todos : [
783+ { id : 0 , title : "Buy milk" , done : false } ,
784+ { id : 1 , title : "Buy eggs" , done : false } ,
785+ { id : 2 , title : "Walk the dog" , done : true } ,
786+ { id : 3 , title : "Buy bread" , done : true }
787+ ] ,
788+ hash : '#/active'
789+ } ;
790+
791+ const model_with_search = app . update ( 'SEARCH' , model , 'Buy' ) ;
792+ document . getElementById ( id ) . appendChild ( app . render_main ( model_with_search , mock_signal ) ) ;
793+
794+ t . equal ( document . querySelectorAll ( '.view' ) . length , 2 , "two active items match 'Buy'" ) ;
795+
796+ elmish . empty ( document . getElementById ( id ) ) ;
797+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
798+ t . end ( ) ;
799+ } ) ;
800+
801+ test ( '10.5 Search > footer should still show original counts when searching' , function ( t ) {
802+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
803+ elmish . empty ( document . getElementById ( id ) ) ;
804+ const model = {
805+ todos : [
806+ { id : 0 , title : "Buy milk" , done : false } ,
807+ { id : 1 , title : "Buy eggs" , done : false } ,
808+ { id : 2 , title : "Walk the dog" , done : true }
809+ ] ,
810+ hash : '#/' ,
811+ search : 'milk'
812+ } ;
813+
814+ document . getElementById ( id ) . appendChild ( app . render_footer ( model ) ) ;
815+
816+ const count = parseInt ( document . getElementById ( 'count' ) . textContent , 10 ) ;
817+ t . equal ( count , 2 , "footer shows 2 items left (original count)" ) ;
818+
819+ const completed_count = parseInt ( document . getElementById ( 'completed-count' ) . textContent , 10 ) ;
820+ t . equal ( completed_count , 1 , "footer shows 1 completed item (original count)" ) ;
821+
822+ elmish . empty ( document . getElementById ( id ) ) ;
823+ localStorage . removeItem ( 'todos-elmish_' + id ) ;
824+ t . end ( ) ;
825+ } ) ;
826+
0 commit comments