X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=tests%2Fqunit%2Fsuites%2Fresources%2Fmediawiki.rcfilters%2Fdm.FiltersViewModel.test.js;h=da7bafdbdb4f32a78d6b6c56effa4d7bfe6ee9b8;hb=4427b84407e03275bdb62ca58a0fde14f3dc7be6;hp=233ec761eefa892638668270e8722a10058864d2;hpb=9e0dda42fec9bfe1b4708d696557325f1dedd771;p=lhc%2Fweb%2Fwiklou.git diff --git a/tests/qunit/suites/resources/mediawiki.rcfilters/dm.FiltersViewModel.test.js b/tests/qunit/suites/resources/mediawiki.rcfilters/dm.FiltersViewModel.test.js index 233ec761ee..da7bafdbdb 100644 --- a/tests/qunit/suites/resources/mediawiki.rcfilters/dm.FiltersViewModel.test.js +++ b/tests/qunit/suites/resources/mediawiki.rcfilters/dm.FiltersViewModel.test.js @@ -1,15 +1,199 @@ /* eslint-disable camelcase */ ( function ( mw, $ ) { + var filterDefinition = [ { + name: 'group1', + type: 'send_unselected_if_any', + filters: [ + { + name: 'filter1', label: 'group1filter1-label', description: 'group1filter1-desc', + default: true, + conflicts: [ { group: 'group2' } ], + subset: [ + { + group: 'group1', + filter: 'filter2' + }, + { + group: 'group1', + filter: 'filter3' + } + ] + }, + { + name: 'filter2', label: 'group1filter2-label', description: 'group1filter2-desc', + conflicts: [ { group: 'group2', filter: 'filter6' } ], + subset: [ + { + group: 'group1', + filter: 'filter3' + } + ] + }, + { name: 'filter3', label: 'group1filter3-label', description: 'group1filter3-desc', default: true } + ] + }, { + name: 'group2', + type: 'send_unselected_if_any', + fullCoverage: true, + conflicts: [ { group: 'group1', filter: 'filter1' } ], + filters: [ + { name: 'filter4', label: 'group2filter4-label', description: 'group2filter4-desc' }, + { name: 'filter5', label: 'group2filter5-label', description: 'group2filter5-desc', default: true }, + { + name: 'filter6', label: 'group2filter6-label', description: 'group2filter6-desc', + conflicts: [ { group: 'group1', filter: 'filter2' } ] + } + ] + }, { + name: 'group3', + type: 'string_options', + separator: ',', + default: 'filter8', + filters: [ + { name: 'filter7', label: 'group3filter7-label', description: 'group3filter7-desc' }, + { name: 'filter8', label: 'group3filter8-label', description: 'group3filter8-desc' }, + { name: 'filter9', label: 'group3filter9-label', description: 'group3filter9-desc' } + ] + }, { + name: 'group4', + type: 'single_option', + default: 'option2', + filters: [ + { name: 'option1', label: 'group4option1-label', description: 'group4option1-desc' }, + { name: 'option2', label: 'group4option2-label', description: 'group4option2-desc' }, + { name: 'option3', label: 'group4option3-label', description: 'group4option3-desc' } + ] + }, { + name: 'group5', + type: 'single_option', + filters: [ + { name: 'option1', label: 'group5option1-label', description: 'group5option1-desc' }, + { name: 'option2', label: 'group5option2-label', description: 'group5option2-desc' }, + { name: 'option3', label: 'group5option3-label', description: 'group5option3-desc' } + ] + }, { + name: 'group6', + type: 'boolean', + filters: [ + { name: 'group6option1', label: 'group6option1-label', description: 'group5option1-desc' }, + { name: 'group6option2', label: 'group6option2-label', description: 'group5option2-desc', default: true, useDefaultAsBaseValue: true }, + { name: 'group6option3', label: 'group6option3-label', description: 'group5option3-desc', default: true } + ] + } ], + viewsDefinition = { + namespaces: { + label: 'Namespaces', + trigger: ':', + groups: [ { + name: 'namespace', + label: 'Namespaces', + type: 'string_options', + separator: ';', + filters: [ + { name: 0, label: 'Main' }, + { name: 1, label: 'Talk' }, + { name: 2, label: 'User' }, + { name: 3, label: 'User talk' } + ] + } ] + } + }, + defaultParameters = { + filter1: '1', + filter2: '0', + filter3: '1', + filter4: '0', + filter5: '1', + filter6: '0', + group3: 'filter8', + group4: 'option2', + group5: 'option1', + group6option1: '0', + group6option2: '1', + group6option3: '1', + namespace: '' + }, + baseParamRepresentation = { + filter1: '0', + filter2: '0', + filter3: '0', + filter4: '0', + filter5: '0', + filter6: '0', + group3: '', + group4: 'option2', + group5: 'option1', + group6option1: '0', + group6option2: '1', + group6option3: '0', + namespace: '' + }, + baseFilterRepresentation = { + group1__filter1: false, + group1__filter2: false, + group1__filter3: false, + group2__filter4: false, + group2__filter5: false, + group2__filter6: false, + group3__filter7: false, + group3__filter8: false, + group3__filter9: false, + // The 'single_value' type of group can't have empty value; it's either + // the default given or the first item that will get the truthy value + group4__option1: false, + group4__option2: true, // Default + group4__option3: false, + group5__option1: true, // No default set, first item is default value + group5__option2: false, + group5__option3: false, + group6__group6option1: false, + group6__group6option2: true, + group6__group6option3: false, + namespace__0: false, + namespace__1: false, + namespace__2: false, + namespace__3: false + }, + baseFullFilterState = { + group1__filter1: { selected: false, conflicted: false, included: false }, + group1__filter2: { selected: false, conflicted: false, included: false }, + group1__filter3: { selected: false, conflicted: false, included: false }, + group2__filter4: { selected: false, conflicted: false, included: false }, + group2__filter5: { selected: false, conflicted: false, included: false }, + group2__filter6: { selected: false, conflicted: false, included: false }, + group3__filter7: { selected: false, conflicted: false, included: false }, + group3__filter8: { selected: false, conflicted: false, included: false }, + group3__filter9: { selected: false, conflicted: false, included: false }, + group4__option1: { selected: false, conflicted: false, included: false }, + group4__option2: { selected: true, conflicted: false, included: false }, + group4__option3: { selected: false, conflicted: false, included: false }, + group5__option1: { selected: true, conflicted: false, included: false }, + group5__option2: { selected: false, conflicted: false, included: false }, + group5__option3: { selected: false, conflicted: false, included: false }, + group6__group6option1: { selected: false, conflicted: false, included: false }, + group6__group6option2: { selected: true, conflicted: false, included: false }, + group6__group6option3: { selected: false, conflicted: false, included: false }, + namespace__0: { selected: false, conflicted: false, included: false }, + namespace__1: { selected: false, conflicted: false, included: false }, + namespace__2: { selected: false, conflicted: false, included: false }, + namespace__3: { selected: false, conflicted: false, included: false } + }; + QUnit.module( 'mediawiki.rcfilters - FiltersViewModel', QUnit.newMwEnvironment( { messages: { - 'group1filter1-label': 'Group 1: Filter 1', + 'group1filter1-label': 'Group 1: Filter 1 title', 'group1filter1-desc': 'Description of Filter 1 in Group 1', - 'group1filter2-label': 'Group 1: Filter 2', + 'group1filter2-label': 'Group 1: Filter 2 title', 'group1filter2-desc': 'Description of Filter 2 in Group 1', - 'group2filter1-label': 'Group 2: Filter 1', - 'group2filter1-desc': 'Description of Filter 1 in Group 2', - 'group2filter2-label': 'xGroup 2: Filter 2', - 'group2filter2-desc': 'Description of Filter 2 in Group 2' + 'group1filter3-label': 'Group 1: Filter 3', + 'group1filter3-desc': 'Description of Filter 3 in Group 1', + + 'group2filter4-label': 'Group 2: Filter 4 title', + 'group2filter4-desc': 'Description of Filter 4 in Group 2', + 'group2filter5-label': 'Group 2: Filter 5', + 'group2filter5-desc': 'Description of Filter 5 in Group 2', + 'group2filter6-label': 'xGroup 2: Filter 6', + 'group2filter6-desc': 'Description of Filter 6 in Group 2' }, config: { wgStructuredChangeFiltersEnableExperimentalViews: true @@ -17,265 +201,68 @@ } ) ); QUnit.test( 'Setting up filters', function ( assert ) { - var definition = [ { - name: 'group1', - title: 'Group 1', - type: 'send_unselected_if_any', - filters: [ - { - name: 'filter1', - label: 'Group 1: Filter 1', - description: 'Description of Filter 1 in Group 1' - }, - { - name: 'filter2', - label: 'Group 1: Filter 2', - description: 'Description of Filter 2 in Group 1' - } - ] - }, { - name: 'group2', - title: 'Group 2', - type: 'send_unselected_if_any', - filters: [ - { - name: 'filter1', - label: 'Group 2: Filter 1', - description: 'Description of Filter 1 in Group 2' - }, - { - name: 'filter2', - label: 'Group 2: Filter 2', - description: 'Description of Filter 2 in Group 2' - } - ] - }, { - name: 'group3', - title: 'Group 3', - type: 'string_options', - filters: [ - { - name: 'filter1', - label: 'Group 3: Filter 1', - description: 'Description of Filter 1 in Group 3' - }, - { - name: 'filter2', - label: 'Group 3: Filter 2', - description: 'Description of Filter 2 in Group 3' - } - ] - } ], - namespaces = { - 0: 'Main', - 1: 'Talk', - 2: 'User', - 3: 'User talk' - }, - model = new mw.rcfilters.dm.FiltersViewModel(); + var model = new mw.rcfilters.dm.FiltersViewModel(); - model.initializeFilters( definition, namespaces ); + model.initializeFilters( filterDefinition, viewsDefinition ); + // Test that all items were created assert.ok( - model.getItemByName( 'group1__filter1' ) instanceof mw.rcfilters.dm.FilterItem && - model.getItemByName( 'group1__filter2' ) instanceof mw.rcfilters.dm.FilterItem && - model.getItemByName( 'group2__filter1' ) instanceof mw.rcfilters.dm.FilterItem && - model.getItemByName( 'group2__filter2' ) instanceof mw.rcfilters.dm.FilterItem && - model.getItemByName( 'group3__filter1' ) instanceof mw.rcfilters.dm.FilterItem && - model.getItemByName( 'group3__filter2' ) instanceof mw.rcfilters.dm.FilterItem, - model.getItemByName( 'namespace__0' ) instanceof mw.rcfilters.dm.FilterItem, - model.getItemByName( 'namespace__1' ) instanceof mw.rcfilters.dm.FilterItem, - model.getItemByName( 'namespace__2' ) instanceof mw.rcfilters.dm.FilterItem, - model.getItemByName( 'namespace__3' ) instanceof mw.rcfilters.dm.FilterItem, + Object.keys( baseFilterRepresentation ).every( function ( filterName ) { + return model.getItemByName( filterName ) instanceof mw.rcfilters.dm.FilterItem; + } ), 'Filters instantiated and stored correctly' ); assert.deepEqual( model.getSelectedState(), - { - group1__filter1: false, - group1__filter2: false, - group2__filter1: false, - group2__filter2: false, - group3__filter1: false, - group3__filter2: false, - namespace__0: false, - namespace__1: false, - namespace__2: false, - namespace__3: false - }, + baseFilterRepresentation, 'Initial state of filters' ); model.toggleFiltersSelected( { group1__filter1: true, - group2__filter2: true, - group3__filter1: true + group2__filter5: true, + group3__filter7: true } ); assert.deepEqual( model.getSelectedState(), - { + $.extend( true, {}, baseFilterRepresentation, { group1__filter1: true, - group1__filter2: false, - group2__filter1: false, - group2__filter2: true, - group3__filter1: true, - group3__filter2: false, - namespace__0: false, - namespace__1: false, - namespace__2: false, - namespace__3: false - }, + group2__filter5: true, + group3__filter7: true + } ), 'Updating filter states correctly' ); } ); QUnit.test( 'Default filters', function ( assert ) { - var definition = [ { - name: 'group1', - title: 'Group 1', - type: 'send_unselected_if_any', - filters: [ - { - name: 'hidefilter1', - label: 'Show filter 1', - description: 'Description of Filter 1 in Group 1', - default: true - }, - { - name: 'hidefilter2', - label: 'Show filter 2', - description: 'Description of Filter 2 in Group 1' - }, - { - name: 'hidefilter3', - label: 'Show filter 3', - description: 'Description of Filter 3 in Group 1', - default: true - } - ] - }, { - name: 'group2', - title: 'Group 2', - type: 'send_unselected_if_any', - filters: [ - { - name: 'hidefilter4', - label: 'Show filter 4', - description: 'Description of Filter 1 in Group 2' - }, - { - name: 'hidefilter5', - label: 'Show filter 5', - description: 'Description of Filter 2 in Group 2', - default: true - }, - { - name: 'hidefilter6', - label: 'Show filter 6', - description: 'Description of Filter 3 in Group 2' - } - ] - }, { + var model = new mw.rcfilters.dm.FiltersViewModel(); - name: 'group3', - title: 'Group 3', - type: 'string_options', - separator: ',', - default: 'filter8', - filters: [ - { - name: 'filter7', - label: 'Group 3: Filter 1', - description: 'Description of Filter 1 in Group 3' - }, - { - name: 'filter8', - label: 'Group 3: Filter 2', - description: 'Description of Filter 2 in Group 3' - }, - { - name: 'filter9', - label: 'Group 3: Filter 3', - description: 'Description of Filter 3 in Group 3' - } - ] - } ], - model = new mw.rcfilters.dm.FiltersViewModel(); - - model.initializeFilters( definition ); + model.initializeFilters( filterDefinition, viewsDefinition ); // Empty query = only default values assert.deepEqual( model.getDefaultParams(), - { - hidefilter1: '1', - hidefilter2: '0', - hidefilter3: '1', - hidefilter4: '0', - hidefilter5: '1', - hidefilter6: '0', - group3: 'filter8' - }, + defaultParameters, 'Default parameters are stored properly per filter and group' ); } ); QUnit.test( 'Finding matching filters', function ( assert ) { var matches, - definition = [ { - name: 'group1', - title: 'Group 1 title', - type: 'send_unselected_if_any', - filters: [ - { - name: 'filter1', - label: 'group1filter1-label', - description: 'group1filter1-desc' - }, - { - name: 'filter2', - label: 'group1filter2-label', - description: 'group1filter2-desc' - } - ] - }, { - name: 'group2', - title: 'Group 2 title', - type: 'send_unselected_if_any', - filters: [ - { - name: 'filter1', - label: 'group2filter1-label', - description: 'group2filter1-desc' - }, - { - name: 'filter2', - label: 'group2filter2-label', - description: 'group2filter2-desc' - } - ] - } ], - namespaces = { - 0: 'Main', - 1: 'Talk', - 2: 'User', - 3: 'User talk' - }, testCases = [ { query: 'group', expectedMatches: { - group1: [ 'group1__filter1', 'group1__filter2' ], - group2: [ 'group2__filter1' ] + group1: [ 'group1__filter1', 'group1__filter2', 'group1__filter3' ], + group2: [ 'group2__filter4', 'group2__filter5' ] }, reason: 'Finds filters starting with the query string' }, { - query: 'filter 2 in group', + query: 'in Group 2', expectedMatches: { - group1: [ 'group1__filter2' ], - group2: [ 'group2__filter2' ] + group2: [ 'group2__filter4', 'group2__filter5', 'group2__filter6' ] }, reason: 'Finds filters containing the query string in their description' }, @@ -283,7 +270,7 @@ query: 'title', expectedMatches: { group1: [ 'group1__filter1', 'group1__filter2' ], - group2: [ 'group2__filter1', 'group2__filter2' ] + group2: [ 'group2__filter4' ] }, reason: 'Finds filters containing the query string in their group title' }, @@ -292,7 +279,7 @@ expectedMatches: { namespace: [ 'namespace__0' ] }, - reason: 'Finds namespaces when using : prefix' + reason: 'Finds item in view when a prefix is used' }, { query: ':group', @@ -311,7 +298,7 @@ return result; }; - model.initializeFilters( definition, namespaces ); + model.initializeFilters( filterDefinition, viewsDefinition ); testCases.forEach( function ( testCase ) { matches = model.findMatches( testCase.query ); @@ -330,165 +317,57 @@ } ); QUnit.test( 'getParametersFromFilters', function ( assert ) { - var definition = [ { - name: 'group1', - title: 'Group 1', - type: 'send_unselected_if_any', - filters: [ - { - name: 'hidefilter1', - label: 'Group 1: Filter 1', - description: 'Description of Filter 1 in Group 1' - }, - { - name: 'hidefilter2', - label: 'Group 1: Filter 2', - description: 'Description of Filter 2 in Group 1' - }, - { - name: 'hidefilter3', - label: 'Group 1: Filter 3', - description: 'Description of Filter 3 in Group 1' - } - ] - }, { - name: 'group2', - title: 'Group 2', - type: 'send_unselected_if_any', - filters: [ - { - name: 'hidefilter4', - label: 'Group 2: Filter 1', - description: 'Description of Filter 1 in Group 2' - }, - { - name: 'hidefilter5', - label: 'Group 2: Filter 2', - description: 'Description of Filter 2 in Group 2' - }, - { - name: 'hidefilter6', - label: 'Group 2: Filter 3', - description: 'Description of Filter 3 in Group 2' - } - ] - }, { - name: 'group3', - title: 'Group 3', - type: 'string_options', - separator: ',', - filters: [ - { - name: 'filter7', - label: 'Group 3: Filter 1', - description: 'Description of Filter 1 in Group 3' - }, - { - name: 'filter8', - label: 'Group 3: Filter 2', - description: 'Description of Filter 2 in Group 3' - }, - { - name: 'filter9', - label: 'Group 3: Filter 3', - description: 'Description of Filter 3 in Group 3' - } - ] - } ], - model = new mw.rcfilters.dm.FiltersViewModel(); + var model = new mw.rcfilters.dm.FiltersViewModel(); - model.initializeFilters( definition ); + model.initializeFilters( filterDefinition, viewsDefinition ); // Starting with all filters unselected assert.deepEqual( model.getParametersFromFilters(), - { - hidefilter1: '0', - hidefilter2: '0', - hidefilter3: '0', - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', - group3: '' - }, + baseParamRepresentation, 'Unselected filters return all parameters falsey or \'\'.' ); // Select 1 filter model.toggleFiltersSelected( { - group1__hidefilter1: true, - group1__hidefilter2: false, - group1__hidefilter3: false, - group2__hidefilter4: false, - group2__hidefilter5: false, - group2__hidefilter6: false + group1__filter1: true } ); // Only one filter in one group assert.deepEqual( model.getParametersFromFilters(), - { + $.extend( true, {}, baseParamRepresentation, { // Group 1 (one selected, the others are true) - hidefilter1: '0', - hidefilter2: '1', - hidefilter3: '1', - // Group 2 (nothing is selected, all false) - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', - group3: '' - }, + filter2: '1', + filter3: '1' + } ), 'One filter in one "send_unselected_if_any" group returns the other parameters truthy.' ); // Select 2 filters model.toggleFiltersSelected( { - group1__hidefilter1: true, - group1__hidefilter2: true, - group1__hidefilter3: false, - group2__hidefilter4: false, - group2__hidefilter5: false, - group2__hidefilter6: false + group1__filter1: true, + group1__filter2: true } ); // Two selected filters in one group assert.deepEqual( model.getParametersFromFilters(), - { - // Group 1 (two selected, the others are true) - hidefilter1: '0', - hidefilter2: '0', - hidefilter3: '1', - // Group 2 (nothing is selected, all false) - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', - group3: '' - }, + $.extend( true, {}, baseParamRepresentation, { + // Group 1 (two selected, the other is true) + filter3: '1' + } ), 'Two filters in one "send_unselected_if_any" group returns the other parameters truthy.' ); // Select 3 filters model.toggleFiltersSelected( { - group1__hidefilter1: true, - group1__hidefilter2: true, - group1__hidefilter3: true, - group2__hidefilter4: false, - group2__hidefilter5: false, - group2__hidefilter6: false + group1__filter1: true, + group1__filter2: true, + group1__filter3: true } ); // All filters of the group are selected == this is the same as not selecting any assert.deepEqual( model.getParametersFromFilters(), - { - // Group 1 (all selected, all false) - hidefilter1: '0', - hidefilter2: '0', - hidefilter3: '0', - // Group 2 (nothing is selected, all false) - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', - group3: '' - }, + baseParamRepresentation, 'All filters selected in one "send_unselected_if_any" group returns all parameters falsy.' ); @@ -501,17 +380,9 @@ // All filters of the group are selected == this is the same as not selecting any assert.deepEqual( model.getParametersFromFilters(), - { - // Group 1 (all selected, all) - hidefilter1: '0', - hidefilter2: '0', - hidefilter3: '0', - // Group 2 (nothing is selected, all false) - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', + $.extend( true, {}, baseParamRepresentation, { group3: 'filter7' - }, + } ), 'One filter selected in "string_option" group returns that filter in the value.' ); @@ -524,17 +395,9 @@ // All filters of the group are selected == this is the same as not selecting any assert.deepEqual( model.getParametersFromFilters(), - { - // Group 1 (all selected, all) - hidefilter1: '0', - hidefilter2: '0', - hidefilter3: '0', - // Group 2 (nothing is selected, all false) - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', + $.extend( true, {}, baseParamRepresentation, { group3: 'filter7,filter8' - }, + } ), 'Two filters selected in "string_option" group returns those filters in the value.' ); @@ -547,23 +410,47 @@ // All filters of the group are selected == this is the same as not selecting any assert.deepEqual( model.getParametersFromFilters(), - { - // Group 1 (all selected, all) - hidefilter1: '0', - hidefilter2: '0', - hidefilter3: '0', - // Group 2 (nothing is selected, all false) - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', + $.extend( true, {}, baseParamRepresentation, { group3: 'all' - }, + } ), 'All filters selected in "string_option" group returns \'all\'.' ); + // Reset + model = new mw.rcfilters.dm.FiltersViewModel(); + model.initializeFilters( filterDefinition, viewsDefinition ); + + // Select an option from single_option group + model.toggleFiltersSelected( { + group4__option2: true + } ); + // All filters of the group are selected == this is the same as not selecting any + assert.deepEqual( + model.getParametersFromFilters(), + $.extend( true, {}, baseParamRepresentation, { + group4: 'option2' + } ), + 'Selecting an option from "single_option" group returns that option as a value.' + ); + + // Select a different option from single_option group + model.toggleFiltersSelected( { + group4__option3: true + } ); + // All filters of the group are selected == this is the same as not selecting any + assert.deepEqual( + model.getParametersFromFilters(), + $.extend( true, {}, baseParamRepresentation, { + group4: 'option3' + } ), + 'Selecting a different option from "single_option" group changes the selection.' + ); } ); QUnit.test( 'getParametersFromFilters (custom object)', function ( assert ) { + // This entire test uses different base definition than the global one + // on purpose, to verify that the values inserted as a custom object + // are the ones we expect in return var originalState, model = new mw.rcfilters.dm.FiltersViewModel(), definition = [ { @@ -594,7 +481,26 @@ { name: 'filter8', label: 'Hide filter 8', description: '' }, { name: 'filter9', label: 'Hide filter 9', description: '' } ] + }, { + name: 'group4', + title: 'Group 4', + type: 'single_option', + filters: [ + { name: 'filter10', label: 'Hide filter 10', description: '' }, + { name: 'filter11', label: 'Hide filter 11', description: '' }, + { name: 'filter12', label: 'Hide filter 12', description: '' } + ] } ], + baseResult = { + hidefilter1: '0', + hidefilter2: '0', + hidefilter3: '0', + hidefilter4: '0', + hidefilter5: '0', + hidefilter6: '0', + group3: '', + group4: '' + }, cases = [ { // This is mocking the cases above, both @@ -611,17 +517,12 @@ group3__filter8: true, group3__filter9: false }, - expected: { + expected: $.extend( true, {}, baseResult, { // Group 1 (two selected, the others are true) - hidefilter1: '0', - hidefilter2: '0', hidefilter3: '1', - // Group 2 (nothing is selected, all false) - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', + // Group 3 (two selected) group3: 'filter7,filter8' - }, + } ), msg: 'Given an explicit (complete) filter state object, the result is the same as if the object given represented the model state.' }, { @@ -630,30 +531,35 @@ input: { group1__hidefilter1: 1 }, - expected: { + expected: $.extend( true, {}, baseResult, { // Group 1 (one selected, the others are true) - hidefilter1: '0', hidefilter2: '1', - hidefilter3: '1', - // Group 2 (nothing is selected, all false) - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', - group3: '' - }, + hidefilter3: '1' + } ), msg: 'Given an explicit (incomplete) filter state object, the result is the same as if the object give represented the model state.' }, { - input: {}, - expected: { - hidefilter1: '0', - hidefilter2: '0', - hidefilter3: '0', - hidefilter4: '0', - hidefilter5: '0', - hidefilter6: '0', - group3: '' + input: { + group4__filter10: true + }, + expected: $.extend( true, {}, baseResult, { + group4: 'filter10' + } ), + msg: 'Given a single value for "single_option" that option is represented in the result.' + }, + { + input: { + group4__filter10: true, + group4__filter11: true }, + expected: $.extend( true, {}, baseResult, { + group4: 'filter10' + } ), + msg: 'Given more than one true value for "single_option" (which should not happen!) only the first value counts, and the second is ignored.' + }, + { + input: {}, + expected: baseResult, msg: 'Given an explicit empty object, the result is all filters set to their falsey unselected value.' } ]; @@ -681,120 +587,39 @@ } ); QUnit.test( 'getFiltersFromParameters', function ( assert ) { - var definition = [ { - name: 'group1', - title: 'Group 1', - type: 'send_unselected_if_any', - filters: [ - { - name: 'hidefilter1', - label: 'Show filter 1', - description: 'Description of Filter 1 in Group 1', - default: true - }, - { - name: 'hidefilter2', - label: 'Show filter 2', - description: 'Description of Filter 2 in Group 1' - }, - { - name: 'hidefilter3', - label: 'Show filter 3', - description: 'Description of Filter 3 in Group 1', - default: true - } - ] - }, { - name: 'group2', - title: 'Group 2', - type: 'send_unselected_if_any', - filters: [ - { - name: 'hidefilter4', - label: 'Show filter 4', - description: 'Description of Filter 1 in Group 2' - }, - { - name: 'hidefilter5', - label: 'Show filter 5', - description: 'Description of Filter 2 in Group 2', - default: true - }, - { - name: 'hidefilter6', - label: 'Show filter 6', - description: 'Description of Filter 3 in Group 2' - } - ] - }, { - - name: 'group3', - title: 'Group 3', - type: 'string_options', - separator: ',', - default: 'filter8', - filters: [ - { - name: 'filter7', - label: 'Group 3: Filter 1', - description: 'Description of Filter 1 in Group 3' - }, - { - name: 'filter8', - label: 'Group 3: Filter 2', - description: 'Description of Filter 2 in Group 3' - }, - { - name: 'filter9', - label: 'Group 3: Filter 3', - description: 'Description of Filter 3 in Group 3' - } - ] - } ], - baseFilterRepresentation = { - group1__hidefilter1: false, - group1__hidefilter2: false, - group1__hidefilter3: false, - group2__hidefilter4: false, - group2__hidefilter5: false, - group2__hidefilter6: false, - group3__filter7: false, - group3__filter8: false, - group3__filter9: false - }, - model = new mw.rcfilters.dm.FiltersViewModel(); + var model = new mw.rcfilters.dm.FiltersViewModel(); - model.initializeFilters( definition ); + model.initializeFilters( filterDefinition, viewsDefinition ); // Empty query = only default values assert.deepEqual( model.getFiltersFromParameters( {} ), baseFilterRepresentation, - 'Empty parameter query results in an object representing all filters set to false' + 'Empty parameter query results in an object representing all filters set to their base state' ); assert.deepEqual( model.getFiltersFromParameters( { - hidefilter2: '1' + filter2: '1' } ), $.extend( {}, baseFilterRepresentation, { - group1__hidefilter1: true, // The text is "show filter 1" - group1__hidefilter2: false, // The text is "show filter 2" - group1__hidefilter3: true // The text is "show filter 3" + group1__filter1: true, // The text is "show filter 1" + group1__filter2: false, // The text is "show filter 2" + group1__filter3: true // The text is "show filter 3" } ), 'One truthy parameter in a group whose other parameters are true by default makes the rest of the filters in the group false (unchecked)' ); assert.deepEqual( model.getFiltersFromParameters( { - hidefilter1: '1', - hidefilter2: '1', - hidefilter3: '1' + filter1: '1', + filter2: '1', + filter3: '1' } ), $.extend( {}, baseFilterRepresentation, { - group1__hidefilter1: false, // The text is "show filter 1" - group1__hidefilter2: false, // The text is "show filter 2" - group1__hidefilter3: false // The text is "show filter 3" + group1__filter1: false, // The text is "show filter 1" + group1__filter2: false, // The text is "show filter 2" + group1__filter3: false // The text is "show filter 3" } ), 'All paremeters in the same \'send_unselected_if_any\' group false is equivalent to none are truthy (checked) in the interface' ); @@ -810,13 +635,13 @@ // to the input it receives. model.toggleFiltersSelected( model.getFiltersFromParameters( { - hidefilter1: '1' + filter1: '1' } ) ); model.toggleFiltersSelected( model.getFiltersFromParameters( { - hidefilter6: '1' + filter6: '1' } ) ); @@ -824,16 +649,16 @@ assert.deepEqual( model.getSelectedState(), $.extend( {}, baseFilterRepresentation, { - group2__hidefilter4: true, - group2__hidefilter5: true, - group2__hidefilter6: false + group2__filter4: true, + group2__filter5: true, + group2__filter6: false } ), 'getFiltersFromParameters does not care about previous or existing state.' ); // Reset model = new mw.rcfilters.dm.FiltersViewModel(); - model.initializeFilters( definition ); + model.initializeFilters( filterDefinition, viewsDefinition ); model.toggleFiltersSelected( model.getFiltersFromParameters( { @@ -909,34 +734,54 @@ } ), 'A \'string_options\' parameter containing an invalid value, results in the invalid value ignored and the valid corresponding filters checked.' ); + + model.toggleFiltersSelected( + model.getFiltersFromParameters( { + group4: 'option1' + } ) + ); + assert.deepEqual( + model.getSelectedState(), + $.extend( {}, baseFilterRepresentation, { + group4__option1: true, + group4__option2: false + } ), + 'A \'single_option\' parameter reflects a single selected value.' + ); + + assert.deepEqual( + model.getFiltersFromParameters( { + group4: 'option1,option2' + } ), + baseFilterRepresentation, + 'An invalid \'single_option\' parameter is ignored.' + ); + + // Change to one value + model.toggleFiltersSelected( + model.getFiltersFromParameters( { + group4: 'option1' + } ) + ); + // Change again to another value + model.toggleFiltersSelected( + model.getFiltersFromParameters( { + group4: 'option2' + } ) + ); + assert.deepEqual( + model.getSelectedState(), + $.extend( {}, baseFilterRepresentation, { + group4__option2: true + } ), + 'A \'single_option\' parameter always reflects the latest selected value.' + ); } ); QUnit.test( 'sanitizeStringOptionGroup', function ( assert ) { - var definition = [ { - name: 'group1', - title: 'Group 1', - type: 'string_options', - filters: [ - { - name: 'filter1', - label: 'Show filter 1', - description: 'Description of Filter 1 in Group 1' - }, - { - name: 'filter2', - label: 'Show filter 2', - description: 'Description of Filter 2 in Group 1' - }, - { - name: 'filter3', - label: 'Show filter 3', - description: 'Description of Filter 3 in Group 1' - } - ] - } ], - model = new mw.rcfilters.dm.FiltersViewModel(); + var model = new mw.rcfilters.dm.FiltersViewModel(); - model.initializeFilters( definition ); + model.initializeFilters( filterDefinition, viewsDefinition ); assert.deepEqual( model.sanitizeStringOptionGroup( 'group1', [ 'filter1', 'filter1', 'filter2' ] ), @@ -958,52 +803,10 @@ } ); QUnit.test( 'Filter interaction: subsets', function ( assert ) { - var definition = [ { - name: 'group1', - title: 'Group 1', - type: 'string_options', - filters: [ - { - name: 'filter1', - label: 'Show filter 1', - description: 'Description of Filter 1 in Group 1', - subset: [ - { - group: 'group1', - filter: 'filter2' - }, - { - group: 'group1', - filter: 'filter3' - } - ] - }, - { - name: 'filter2', - label: 'Show filter 2', - description: 'Description of Filter 2 in Group 1', - subset: [ - { - group: 'group1', - filter: 'filter3' - } - ] - }, - { - name: 'filter3', - label: 'Show filter 3', - description: 'Description of Filter 3 in Group 1' - } - ] - } ], - baseFullState = { - group1__filter1: { selected: false, conflicted: false, included: false }, - group1__filter2: { selected: false, conflicted: false, included: false }, - group1__filter3: { selected: false, conflicted: false, included: false } - }, - model = new mw.rcfilters.dm.FiltersViewModel(); + var model = new mw.rcfilters.dm.FiltersViewModel(); + + model.initializeFilters( filterDefinition, viewsDefinition ); - model.initializeFilters( definition ); // Select a filter that has subset with another filter model.toggleFiltersSelected( { group1__filter1: true @@ -1012,10 +815,14 @@ model.reassessFilterInteractions( model.getItemByName( 'group1__filter1' ) ); assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter1: { selected: true }, group1__filter2: { included: true }, - group1__filter3: { included: true } + group1__filter3: { included: true }, + // Conflicts are affected + group2__filter4: { conflicted: true }, + group2__filter5: { conflicted: true }, + group2__filter6: { conflicted: true } } ), 'Filters with subsets are represented in the model.' ); @@ -1027,10 +834,12 @@ model.reassessFilterInteractions( model.getItemByName( 'filter2' ) ); assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter1: { selected: true }, group1__filter2: { selected: true, included: true }, - group1__filter3: { included: true } + group1__filter3: { included: true }, + // Conflicts are affected + group2__filter6: { conflicted: true } } ), 'Filters that have multiple subsets are represented.' ); @@ -1042,9 +851,11 @@ model.reassessFilterInteractions( model.getItemByName( 'group1__filter1' ) ); assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter2: { selected: true, included: false }, - group1__filter3: { included: true } + group1__filter3: { included: true }, + // Conflicts are affected + group2__filter6: { conflicted: true } } ), 'Removing a filter only un-includes its subset if there is no other filter affecting.' ); @@ -1055,34 +866,13 @@ model.reassessFilterInteractions( model.getItemByName( 'group1__filter2' ) ); assert.deepEqual( model.getFullState(), - baseFullState, + baseFullFilterState, 'Removing all supersets also un-includes the subsets.' ); } ); QUnit.test( 'Filter interaction: full coverage', function ( assert ) { - var definition = [ { - name: 'group1', - title: 'Group 1', - type: 'string_options', - fullCoverage: false, - filters: [ - { name: 'filter1', label: '1', description: '1' }, - { name: 'filter2', label: '2', description: '2' }, - { name: 'filter3', label: '3', description: '3' } - ] - }, { - name: 'group2', - title: 'Group 2', - type: 'send_unselected_if_any', - fullCoverage: true, - filters: [ - { name: 'filter4', label: '4', description: '4' }, - { name: 'filter5', label: '5', description: '5' }, - { name: 'filter6', label: '6', description: '6' } - ] - } ], - model = new mw.rcfilters.dm.FiltersViewModel(), + var model = new mw.rcfilters.dm.FiltersViewModel(), isCapsuleItemMuted = function ( filterName ) { var itemModel = model.getItemByName( filterName ), groupModel = itemModel.getGroupModel(); @@ -1114,7 +904,7 @@ group2__filter6: false }; - model.initializeFilters( definition ); + model.initializeFilters( filterDefinition, viewsDefinition ); // Starting state, no selection, all items are non-muted assert.deepEqual( @@ -1183,68 +973,13 @@ } ); QUnit.test( 'Filter interaction: conflicts', function ( assert ) { - var definition = [ { - name: 'group1', - title: 'Group 1', - type: 'string_options', - filters: [ - { - name: 'filter1', - label: '1', - description: '1', - conflicts: [ { group: 'group2' } ] - }, - { - name: 'filter2', - label: '2', - description: '2', - conflicts: [ { group: 'group2', filter: 'filter6' } ] - }, - { - name: 'filter3', - label: '3', - description: '3' - } - ] - }, { - name: 'group2', - title: 'Group 2', - type: 'send_unselected_if_any', - conflicts: [ { group: 'group1', filter: 'filter1' } ], - filters: [ - { - name: 'filter4', - label: '1', - description: '1' - }, - { - name: 'filter5', - label: '5', - description: '5' - }, - { - name: 'filter6', - label: '6', - description: '6', - conflicts: [ { group: 'group1', filter: 'filter2' } ] - } - ] - } ], - baseFullState = { - group1__filter1: { selected: false, conflicted: false, included: false }, - group1__filter2: { selected: false, conflicted: false, included: false }, - group1__filter3: { selected: false, conflicted: false, included: false }, - group2__filter4: { selected: false, conflicted: false, included: false }, - group2__filter5: { selected: false, conflicted: false, included: false }, - group2__filter6: { selected: false, conflicted: false, included: false } - }, - model = new mw.rcfilters.dm.FiltersViewModel(); + var model = new mw.rcfilters.dm.FiltersViewModel(); - model.initializeFilters( definition ); + model.initializeFilters( filterDefinition, viewsDefinition ); assert.deepEqual( model.getFullState(), - baseFullState, + baseFullFilterState, 'Initial state: no conflicts because no selections.' ); @@ -1257,11 +992,14 @@ assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter1: { selected: true }, group2__filter4: { conflicted: true }, group2__filter5: { conflicted: true }, - group2__filter6: { conflicted: true } + group2__filter6: { conflicted: true }, + // Subsets are affected by the selection + group1__filter2: { included: true }, + group1__filter3: { included: true } } ), 'Selecting a filter that conflicts with a group sets all the conflicted group items as "conflicted".' ); @@ -1274,18 +1012,21 @@ assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter1: { selected: true, conflicted: true }, group2__filter4: { selected: true, conflicted: true }, group2__filter5: { conflicted: true }, - group2__filter6: { conflicted: true } + group2__filter6: { conflicted: true }, + // Subsets are affected by the selection + group1__filter2: { included: true }, + group1__filter3: { included: true } } ), 'Selecting a conflicting filter inside a group, sets both sides to conflicted and selected.' ); // Reset model = new mw.rcfilters.dm.FiltersViewModel(); - model.initializeFilters( definition ); + model.initializeFilters( filterDefinition, viewsDefinition ); // Select a filter that has a conflict with a specific filter model.toggleFiltersSelected( { @@ -1295,9 +1036,11 @@ assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter2: { selected: true }, - group2__filter6: { conflicted: true } + group2__filter6: { conflicted: true }, + // Subsets are affected by the selection + group1__filter3: { included: true } } ), 'Selecting a filter that conflicts with another filter sets the other as "conflicted".' ); @@ -1311,7 +1054,7 @@ assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter2: { selected: true, conflicted: true }, group2__filter6: { selected: true, conflicted: true }, // This is added to the conflicts because filter6 is part of group2, @@ -1319,7 +1062,10 @@ // with filter6 which means that filter1 conflicts with filter6 (because it's in group2) // and also because its **own sibling** (filter2) is **also** in conflict with the // selected items in group2 (filter6) - group1__filter1: { conflicted: true } + group1__filter1: { conflicted: true }, + + // Subsets are affected by the selection + group1__filter3: { included: true } } ), 'Selecting a conflicting filter with an individual filter, sets both sides to conflicted and selected.' ); @@ -1333,14 +1079,17 @@ assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter2: { selected: true }, group2__filter6: { selected: true }, - group2__filter5: { selected: true } + group2__filter5: { selected: true }, // Filter6 and filter1 are no longer in conflict because // filter5, while it is in conflict with filter1, it is // not in conflict with filter2 - and since filter2 is // selected, it removes the conflict bidirectionally + + // Subsets are affected by the selection + group1__filter3: { included: true } } ), 'Selecting a non-conflicting filter within the group of a conflicting filter removes the conflicts.' ); @@ -1357,7 +1106,7 @@ assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter1: { conflicted: true }, group2__filter6: { selected: true }, group2__filter5: { selected: true } @@ -1374,11 +1123,14 @@ assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter1: { selected: true, conflicted: true }, group2__filter6: { selected: true, conflicted: true }, group2__filter5: { selected: true, conflicted: true }, - group2__filter4: { conflicted: true } // Not selected but conflicted because it's in group2 + group2__filter4: { conflicted: true }, // Not selected but conflicted because it's in group2 + // Subsets are affected by the selection + group1__filter2: { included: true }, + group1__filter3: { included: true } } ), 'Selecting an item that conflicts with a whole group makes all selections in that group conflicted.' ); @@ -1386,7 +1138,7 @@ /* Simple case */ // Reset model = new mw.rcfilters.dm.FiltersViewModel(); - model.initializeFilters( definition ); + model.initializeFilters( filterDefinition, viewsDefinition ); // Select a filter that has a conflict with a specific filter model.toggleFiltersSelected( { @@ -1397,9 +1149,11 @@ assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter2: { selected: true }, - group2__filter6: { conflicted: true } + group2__filter6: { conflicted: true }, + // Subsets are affected by the selection + group1__filter3: { included: true } } ), 'Simple case: Selecting a filter that conflicts with another filter sets the other as "conflicted".' ); @@ -1412,16 +1166,17 @@ assert.deepEqual( model.getFullState(), - $.extend( true, {}, baseFullState, { + $.extend( true, {}, baseFullFilterState, { group1__filter2: { selected: true }, - group1__filter3: { selected: true } + // Subsets are affected by the selection + group1__filter3: { selected: true, included: true } } ), 'Simple case: Selecting a filter that is not in conflict removes the conflict.' ); - } ); QUnit.test( 'Filter highlights', function ( assert ) { + // We are using a different (smaller) definition here than the global one var definition = [ { name: 'group1', title: 'Group 1',