diff --git a/pontoon/base/tests/managers/test_entity.py b/pontoon/base/tests/managers/test_entity.py index 513d1a246f..4d6dcca908 100644 --- a/pontoon/base/tests/managers/test_entity.py +++ b/pontoon/base/tests/managers/test_entity.py @@ -1080,6 +1080,354 @@ def test_mgr_entity_filter_combined(admin, resource_a, locale_a, user_a): ) +@pytest.mark.django_db +def test_mgr_entity_option_match_case(admin, resource_a, locale_a, user_a): + entities = [ + EntityFactory.create( + key="key %s" % i, + resource=resource_a, + string="TestEntity%s" % i, + ) + for i in range(0, 2) + ] + + TranslationFactory.create( + locale=locale_a, + entity=entities[0], + rejected=True, + user=user_a, + ) + TranslationFactory.create( + locale=locale_a, + entity=entities[1], + approved=True, + user=user_a, + ) + + args = [admin, resource_a.project, locale_a] + kwargs = {"search": "testentity", "author": user_a.email} + + # Base case + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[i] for i in range(0, 2)] + + # Test search_match_case + kwargs["search_match_case"] = True + assert ( + list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) + == [] + ) + + +@pytest.mark.django_db +def test_mgr_entity_option_match_whole_word(admin, resource_a, locale_a, user_a): + entities = [ + EntityFactory.create( + resource=resource_a, + string="TestEntity%s" % i, + ) + for i in range(0, 2) + ] + + TranslationFactory.create( + locale=locale_a, + entity=entities[0], + rejected=True, + user=user_a, + ) + TranslationFactory.create( + locale=locale_a, + entity=entities[1], + approved=True, + user=user_a, + ) + + args = [admin, resource_a.project, locale_a] + kwargs = {"search": "TestEntity", "author": user_a.email} + + # Base case + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[i] for i in range(0, 2)] + + kwargs["search_match_whole_word"] = True + # Test search_match_whole_word + assert ( + list( + Entity.for_project_locale( + admin, + resource_a.project, + locale_a, + search="TestEntity", + search_match_whole_word=True, + author=user_a.email, + ) + ) + == [] + ) + + +@pytest.mark.django_db +def test_mgr_entity_option_identifiers(admin, resource_a, locale_a, user_a): + entities = [ + EntityFactory.create( + key="key %s" % i, + resource=resource_a, + string="TestEntity%s" % i, + ) + for i in range(0, 2) + ] + + TranslationFactory.create( + locale=locale_a, + entity=entities[0], + rejected=True, + user=user_a, + ) + TranslationFactory.create( + locale=locale_a, + entity=entities[1], + approved=True, + user=user_a, + ) + + args = [admin, resource_a.project, locale_a] + kwargs = {"search": "key", "author": user_a.email} + + # Base case + assert ( + list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) + == [] + ) + + kwargs["search_identifiers"] = True + # Test search_identifiers + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[i] for i in range(0, 2)] + + +@pytest.mark.django_db +def test_mgr_entity_option_rejected_translations(admin, resource_a, locale_a, user_a): + entities = [ + EntityFactory.create( + resource=resource_a, + string="TestEntity%s" % i, + ) + for i in range(0, 2) + ] + + TranslationFactory.create( + locale=locale_a, + entity=entities[0], + rejected=True, + string="TestString", + user=user_a, + ) + TranslationFactory.create( + locale=locale_a, + entity=entities[1], + approved=True, + string="TestString", + user=user_a, + ) + + args = [admin, resource_a.project, locale_a] + kwargs = {"search": "TestString", "author": user_a.email} + + # Base case + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[1]] + + kwargs["search_rejected_translations"] = True + # Test search_rejected_translations + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[i] for i in range(0, 2)] + + +@pytest.mark.django_db +def test_mgr_entity_option_exclude_source_strings(admin, resource_a, locale_a, user_a): + entities = [ + EntityFactory.create( + resource=resource_a, + string="TestEntity%s" % i, + ) + for i in range(0, 2) + ] + + TranslationFactory.create( + locale=locale_a, + entity=entities[0], + rejected=True, + user=user_a, + ) + TranslationFactory.create( + locale=locale_a, + entity=entities[1], + approved=True, + user=user_a, + ) + + args = [admin, resource_a.project, locale_a] + kwargs = {"search": "TestEntity", "author": user_a.email} + + # Base case + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[i] for i in range(0, 2)] + + kwargs["search_exclude_source_strings"] = True + # Test search_exclude_source_strings + assert ( + list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) + == [] + ) + + +@pytest.mark.django_db +def test_mgr_entity_option_combined(admin, resource_a, locale_a, user_a): + """ + Test combinations of filters + """ + + entities = [ + EntityFactory.create( + key="key %s" % i, + resource=resource_a, + string="TestEntity%s" % i, + ) + for i in range(0, 2) + ] + + TranslationFactory.create( + locale=locale_a, + entity=entities[0], + rejected=True, + string="Translation 0", + user=user_a, + ) + TranslationFactory.create( + locale=locale_a, + entity=entities[1], + approved=True, + string="Translation 1", + user=user_a, + ) + + args = [admin, resource_a.project, locale_a] + kwargs = {} + + # Base case + kwargs = { + "search": "", + "author": user_a.email, + } + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[i] for i in range(0, 2)] + + # Test exclude_source_strings with identifiers + kwargs = { + "search": "key", + "search_exclude_source_strings": True, + "search_identifiers": True, + "author": user_a.email, + } + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[i] for i in range(0, 2)] + + # Test identifiers with match_whole_word + kwargs = { + "search": "key", + "search_match_whole_word": True, + "search_identifiers": True, + "author": user_a.email, + } + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[i] for i in range(0, 2)] + + # Test match_case with match_whole_word + kwargs = { + "search": "translation", + "search_match_case": True, + "search_match_whole_word": True, + "author": user_a.email, + } + assert ( + list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) + == [] + ) + + # Test all options at once + kwargs = { + "search": "Translation", + "search_match_case": True, + "search_match_whole_word": True, + "search_identifiers": True, + "search_rejected_translations": True, + "search_exclude_source_strings": True, + "author": user_a.email, + } + assert list( + Entity.for_project_locale( + *args, + **kwargs, + ) + ) == [entities[i] for i in range(0, 2)] + + @pytest.mark.django_db def test_mgr_entity_search_invalid_query(entity_test_search): """ diff --git a/translate/src/modules/search/components/SearchPanel.test.js b/translate/src/modules/search/components/SearchPanel.test.js new file mode 100644 index 0000000000..36ec07653e --- /dev/null +++ b/translate/src/modules/search/components/SearchPanel.test.js @@ -0,0 +1,75 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import sinon from 'sinon'; + +import { createReduxStore, mountComponentWithStore } from '~/test/store'; + +import { SearchPanel, SearchPanelDialog } from './SearchPanel'; +import { SEARCH_OPTIONS } from '../constants'; + +const selectedSearchOptions = { + search_identifiers: false, + search_exclude_source_strings: false, + search_rejected_translations: true, + search_match_case: true, + search_match_whole_word: false, +}; + +describe('', () => { + it('correctly sets search option as selected', () => { + const store = createReduxStore(); + const wrapper = mountComponentWithStore(SearchPanelDialog, store, { + options: selectedSearchOptions, + selectedSearchOptions, + }); + + for (let { slug } of SEARCH_OPTIONS) { + expect(wrapper.find(`.menu .${slug}`).hasClass('enabled')).toBe( + selectedSearchOptions[slug], + ); + } + }); + + for (let { slug } of SEARCH_OPTIONS) { + describe(`option: ${slug}`, () => { + it('toggles a search option on click on the option icon', () => { + const onToggleOption = sinon.spy(); + const store = createReduxStore(); + + const wrapper = mountComponentWithStore(SearchPanelDialog, store, { + selectedSearchOptions: selectedSearchOptions, + onApplyOptions: sinon.spy(), + onToggleOption, + onDiscard: sinon.spy(), + }); + + wrapper.find(`.menu .${slug}`).simulate('click'); + + expect(onToggleOption.calledWith(slug)).toBeTruthy(); + }); + }); + } + + it('applies selected options on click on the Apply button', () => { + const onApplyOptions = sinon.spy(); + const store = createReduxStore(); + const wrapper = mountComponentWithStore(SearchPanelDialog, store, { + selectedSearchOptions: selectedSearchOptions, + onApplyOptions, + }); + + wrapper.find('.search-button').simulate('click'); + + expect(onApplyOptions.called).toBeTruthy(); + }); +}); + +describe('', () => { + it('shows a panel with options on click', () => { + const wrapper = shallow(); + + expect(wrapper.find('SearchPanelDialog')).toHaveLength(0); + wrapper.find('.visibility-switch').simulate('click'); + expect(wrapper.find('SearchPanelDialog')).toHaveLength(1); + }); +});