$(function(){ var $b = $('#builder'); QUnit.module('core', { afterEach: function() { $b.queryBuilder('destroy'); } }); /** * Test invalid filters */ QUnit.test('Invalid filters', function(assert) { assert.initError($b, {}, /Missing filters list/ ); assert.initError($b, {filters: [{}]}, /Missing filter 0 id/ ); assert.initError($b, {filters: [ {id: 'foo'}, {id: 'foo'} ]}, /Filter "foo" already defined/ ); assert.initError($b, {filters: [ {id: 'foo', type: 'bar'} ]}, /Invalid type "bar"/ ); assert.initError($b, {filters: [ {id: 'foo', input: 'bar'} ]}, /Invalid input "bar"/ ); assert.initError($b, {filters: [ {id: 'foo', input: 'radio'} ]}, /Missing filter "foo" values/ ); assert.initError($b, {filters: [ {id:'foo', input: 'select', values:[1,2,3], placeholder: 1, placeholder_value: 1} ]}, /Placeholder of filter "foo" overlaps with one of its values/ ); }); /** * Test getRules with an empty builder */ QUnit.test('Empty builder', function(assert) { assert.expect(3); $b.queryBuilder({ filters: basic_filters }); $('#builder_rule_0 [data-delete]').click(); $b.on('validationError.queryBuilder', function(e, node, error, value) { assert.equal( error[0], 'empty_group', 'Should throw "empty_group" error' ); }); assert.deepEqual( $b.queryBuilder('getRules'), {}, 'Should return empty object' ); $b.queryBuilder('setOptions', { allow_empty: true }); assert.deepEqual( $b.queryBuilder('getRules'), { condition: 'AND', rules: [] }, 'Should return object with no rules' ); }); /** * Test setRules and getRules */ QUnit.test('Set/get rules', function(assert) { $b.queryBuilder({ filters: basic_filters, rules: basic_rules }); assert.rulesMatch( $b.queryBuilder('getRules'), basic_rules, 'Should return object with rules' ); }); /** * Test default filter */ QUnit.test('Default filter', function(assert) { $b.queryBuilder({ default_filter: 'in_stock', filters: basic_filters }); assert.equal( $('[name=builder_rule_0_filter] [value=-1]').length, 1, 'Should have the placeholder filter' ); assert.equal( $('[name=builder_rule_0_filter]').val(), 'in_stock', 'Sould have used "in_stock" as default filter' ); $b.queryBuilder('destroy'); $b.queryBuilder({ display_empty_filter: false, filters: basic_filters }); assert.equal( $('[name=builder_rule_0_filter] [value=-1]').length, 0, 'Should not have the placeholder filter' ); assert.equal( $('[name=builder_rule_0_filter]').val(), 'name', 'Sould have used the first filter as default one' ); }); /** * Test UI events */ QUnit.test('UI events', function(assert) { $b.queryBuilder({ filters: basic_filters }); $('#builder_group_0>.rules-group-header>.group-conditions [value=OR]').trigger('click'); $('[name=builder_rule_0_filter]').val('name').trigger('change'); $('[name=builder_rule_0_operator]').val('not_equal').trigger('change'); $('[name=builder_rule_0_value_0]').val('foo').trigger('change'); $('#builder_group_0>.rules-group-header>.group-actions [data-add=rule]').trigger('click'); $('#builder_group_0>.rules-group-header>.group-actions [data-add=group]').trigger('click'); $('#builder_rule_1 [data-delete=rule]').trigger('click'); $('#builder_group_1 [data-delete=group]').trigger('click'); assert.rulesMatch( $b.queryBuilder('getRules'), rules_after_ui_events, 'Should return correct rules after UI events' ); }); /** * Test filter.operators */ QUnit.test('Change operators', function(assert) { $b.queryBuilder({ filters: filters_for_custom_operators, rules: rules_for_custom_operators, operators: custom_operators }); assert.optionsMatch( $('#builder_rule_0 [name$=_operator] option'), ['equal', 'not_equal'], '"name" filter should have "equal" & "not_equal" operators' ); assert.optionsMatch( $('#builder_rule_1 [name$=_operator] option'), ['less', 'greater'], '"price" filter should have "less" & "greater" operators' ); assert.optionsMatch( $('#builder_rule_2 [name$=_operator] option'), ['before', 'equal', 'after'], '"release" filter should have "before" & "equal" & "after" operators' ); }); /** * Test custom conditions */ QUnit.test('Change conditions', function(assert) { $b.queryBuilder({ filters: basic_filters, conditions: ['AND'] }); assert.optionsMatch( $b.find('[name$=_cond]'), ['AND'], 'Available condition should be AND' ); $b.queryBuilder('destroy'); $b.queryBuilder({ filters: basic_filters, rules: rules_for_custom_conditions, conditions: ['NAND', 'XOR'], default_condition: 'NAND' }); assert.rulesMatch( $b.queryBuilder('getRules'), rules_for_custom_conditions, 'Should return correct rules' ); assert.optionsMatch( $('#builder_group_0 > .rules-group-header [name$=_cond]'), ['NAND', 'XOR'], 'Available onditions should be NAND & XOR' ); assert.equal( $('#builder_group_1 [name$=_cond]:checked').val(), 'XOR', 'The second group should have "XOR" condition selected' ); }); /** * Test icons */ QUnit.test('Change icons', function(assert) { $b.queryBuilder({ filters: basic_filters, icons: icons }); assert.equal( $b.find('[data-add=rule] i').attr('class'), 'fa fa-plus', 'Rule add icon should have been replaced' ); assert.equal( $b.find('[data-delete=rule] i').attr('class'), 'fa fa-times', 'Rule delete icon should have been replaced' ); }); /** * Test readonly */ QUnit.test('Readonly', function(assert) { $b.queryBuilder({ filters: basic_filters, rules: readonly_rules }); assert.ok( $('#builder_rule_0 [data-delete=rule]').length == 0, 'Should hide delete button of "no_delete" rule' ); assert.ok( $('#builder_rule_0').find('input:disabled, select:disabled').length == 0, 'Should not disable inputs of "no_delete" rule' ); assert.ok( $('#builder_rule_1 [data-delete=rule]').length == 0, 'Should hide delete button of "readonly" rule' ); assert.ok( $('#builder_rule_1').find('input:disabled, select:disabled').length == 3, 'Should disable inputs of "readonly" rule' ); $('#builder_group_1 [data-delete=group]').click(); assert.rulesMatch( $b.queryBuilder('getRules'), readonly_rules_after, 'Should not delete group with readonly rule' ); }); /** * Test groups limit */ QUnit.test('No groups', function(assert) { $b.queryBuilder({ filters: basic_filters, allow_groups: false }); assert.ok( $('#builder_group_0 [data-add=group]').length == 0, 'Should not contain group add button' ); assert.throws( function(){ $b.queryBuilder('setRules', basic_rules); }, /No more than 0 groups are allowed/, 'Should throw "No more than 0 groups are allowed" error' ); }); /** * Test optgroups */ QUnit.test('Optgroups', function(assert) { $b.queryBuilder({ filters: optgroups_filters, optgroups: { A: { en: 'AA', fr: 'AAA' }, B: 'BB' }, lang_code: 'fr' }); var options = [], groups = []; $('[name=builder_rule_0_filter]>*').each(function() { if (this.nodeName == 'OPTION') { options.push($(this).val()); } else { var group = []; $(this).find('option').each(function() { group.push($(this).val()); }); options.push(group); groups.push($(this).attr('label')); } }); assert.deepEqual( options, ['-1', ['1', '3', '6'], '2', ['4'], '5', ['7']], 'Filters should have been put in optgroups, solving discontinuities and keeping order' ); assert.deepEqual( groups, ['AAA', 'BB', 'C'], 'Optgroups should have been correctly translated and created when needed' ); }); /** * Test access to defaults */ QUnit.test('Access to defaults', function(assert) { if (QueryBuilder.defaults() == QueryBuilder.DEFAULTS) { assert.push(false, '[copy]', '[original]', 'Should return full copy of defaults'); } else { assert.deepEqual( QueryBuilder.defaults(), QueryBuilder.DEFAULTS, 'Should return full copy of defaults' ); } assert.equal( QueryBuilder.defaults('allow_empty'), QueryBuilder.DEFAULTS.allow_empty, 'Should return a specific default primitive' ); assert.deepEqual( QueryBuilder.defaults('lang'), QueryBuilder.DEFAULTS.lang, 'Should return a specific default object' ); QueryBuilder.defaults({ default_rule_flags: new_default_flags }); assert.deepEqual( QueryBuilder.DEFAULTS.default_rule_flags, new_default_flags, 'Should have modified the default config object' ); }); /** * Test language load */ QUnit.test('Change language', function(assert) { assert.expect(2); var done = assert.async(); $.getScript('../dist/i18n/query-builder.fr.js', function() { $b.queryBuilder({ filters: basic_filters }); assert.equal( $b.find('[data-delete=rule]').text().trim(), 'Supprimer', 'Should be in french' ); $b.queryBuilder('destroy'); $b.queryBuilder({ filters: basic_filters, lang_code: 'en' }); assert.equal( $b.find('[data-delete=rule]').text().trim(), 'Delete', 'Should be in english' ); QueryBuilder.defaults({ lang_code: 'en' }); done(); }); }); var rules_after_ui_events = { condition: 'OR', rules: [{ id: 'name', operator: 'not_equal', value: 'foo' }] }; var filters_for_custom_operators = [{ id: 'name', type: 'string' }, { id: 'price', type: 'double' }, { id: 'release', type: 'date', operators: ['before', 'equal', 'after'] }]; var rules_for_custom_operators = { condition: 'AND', rules: [{ id: 'name', operator: 'equal', value: 'foo' }, { id: 'price', operator: 'less', value: 10 }, { id: 'release', operator: 'before', value: '1995-5-1' }] }; var custom_operators = [ {type: 'equal', nb_inputs: 1, apply_to: ['string']}, {type: 'not_equal', nb_inputs: 1, apply_to: ['string']}, {type: 'less', nb_inputs: 1, apply_to: ['number']}, {type: 'greater', nb_inputs: 1, apply_to: ['number']}, {type: 'before', nb_inputs: 1, apply_to: ['datetime']}, {type: 'after', nb_inputs: 1, apply_to: ['datetime']} ]; var rules_for_custom_conditions = { condition: 'NAND', rules: [{ id: 'name', operator: 'equal', value: 'foo' }, { condition: 'XOR', rules: [{ id: 'name', operator: 'equal', value: 'bar' }] }] }; var icons = { add_group: 'fa fa-plus-circle', add_rule: 'fa fa-plus', remove_rule: 'fa fa-times', remove_group: 'fa fa-times', sort: 'fa fa-sort' }; var readonly_rules = { condition: 'AND', rules: [{ id: 'price', operator: 'less', value: 10.25, flags: { no_delete: true } }, { condition: 'OR', rules: [{ id: 'id', operator: 'not_equal', value: '1234-azer-5678', readonly: true }] }] }; var readonly_rules_after = { condition: 'AND', rules: [{ id: 'price', operator: 'less', value: 10.25 }, { condition: 'OR', rules: [{ id: 'id', operator: 'not_equal', value: '1234-azer-5678' }] }] }; var optgroups_filters = [{ id: '1', optgroup: 'A' }, { id: '2' }, { id: '3', optgroup: 'A' }, { id: '4', optgroup: 'B' }, { id: '5' }, { id: '6', optgroup: 'A' }, { id: '7', optgroup: 'C' }]; var new_default_flags = { filter_readonly: true, operator_readonly: false, value_readonly: true, no_delete: false }; });