Skip to content

Commit

Permalink
Merge branch 'develop' into selenium/people_smoke_tests
Browse files Browse the repository at this point in the history
  • Loading branch information
szymon-kellton authored Jul 9, 2024
2 parents 221dbaa + b878822 commit 0833860
Show file tree
Hide file tree
Showing 24 changed files with 507 additions and 73 deletions.
21 changes: 4 additions & 17 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
Copyright (c) 2014 - 2024 UNICEF. All rights reserved.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License below for more details.

------------------------------------------------------------------------
GNU AFFERO GENERAL PUBLIC LICENSE
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007

Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Expand Down Expand Up @@ -656,7 +643,7 @@ the "copyright" line and a pointer to where the full notice is found.
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

Expand All @@ -671,4 +658,4 @@ specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.
4 changes: 2 additions & 2 deletions backend/hct_mis_api/apps/targeting/mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def processed_mutate(cls, root: Any, info: Any, **kwargs: Any) -> "CreateTargetP
targeting_criteria_input = input_data.get("targeting_criteria")

business_area = BusinessArea.objects.get(slug=input_data.pop("business_area_slug"))
TargetingCriteriaInputValidator.validate(targeting_criteria_input, program.data_collecting_type)
TargetingCriteriaInputValidator.validate(targeting_criteria_input, program)
targeting_criteria = from_input_to_targeting_criteria(targeting_criteria_input, program)
target_population = TargetPopulation(
name=tp_name,
Expand Down Expand Up @@ -251,7 +251,7 @@ def processed_mutate(cls, root: Any, info: Any, **kwargs: Any) -> "UpdateTargetP

if targeting_criteria_input:
should_rebuild_list = True
TargetingCriteriaInputValidator.validate(targeting_criteria_input, program.data_collecting_type)
TargetingCriteriaInputValidator.validate(targeting_criteria_input, program)
targeting_criteria = from_input_to_targeting_criteria(targeting_criteria_input, program)
if target_population.status == TargetPopulation.STATUS_OPEN:
if target_population.targeting_criteria:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,108 @@
}
}

snapshots['TestCreateTargetPopulationMutation::test_create_mutation_target_by_id 5'] = {
'data': {
'createTargetPopulation': {
'targetPopulation': {
'hasEmptyCriteria': True,
'hasEmptyIdsCriteria': False,
'name': 'Test name 5',
'status': 'OPEN',
'targetingCriteria': {
'householdIds': '',
'individualIds': 'IND-33',
'rules': [
]
},
'totalHouseholdsCount': None,
'totalIndividualsCount': None
}
}
}
}

snapshots['TestCreateTargetPopulationMutation::test_create_mutation_target_by_id 6'] = {
'data': {
'createTargetPopulation': None
},
'errors': [
{
'locations': [
{
'column': 7,
'line': 3
}
],
'message': "['The given individuals do not exist in the current program']",
'path': [
'createTargetPopulation'
]
}
]
}

snapshots['TestCreateTargetPopulationMutation::test_create_mutation_target_by_id 7'] = {
'data': {
'createTargetPopulation': {
'targetPopulation': {
'hasEmptyCriteria': True,
'hasEmptyIdsCriteria': False,
'name': 'Test name 7',
'status': 'OPEN',
'targetingCriteria': {
'householdIds': 'HH-1',
'individualIds': '',
'rules': [
]
},
'totalHouseholdsCount': None,
'totalIndividualsCount': None
}
}
}
}

snapshots['TestCreateTargetPopulationMutation::test_create_mutation_target_by_id 8'] = {
'data': {
'createTargetPopulation': None
},
'errors': [
{
'locations': [
{
'column': 7,
'line': 3
}
],
'message': "['The given households do not exist in the current program']",
'path': [
'createTargetPopulation'
]
}
]
}

snapshots['TestCreateTargetPopulationMutation::test_create_mutation_target_by_id 9'] = {
'data': {
'createTargetPopulation': None
},
'errors': [
{
'locations': [
{
'column': 7,
'line': 3
}
],
'message': "['There should be at least 1 rule in target criteria']",
'path': [
'createTargetPopulation'
]
}
]
}

snapshots['TestCreateTargetPopulationMutation::test_create_mutation_with_comparison_method_contains_0_with_permission 1'] = {
'data': {
'createTargetPopulation': None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ def test_create_mutation_target_by_id(self) -> None:
{"householdIds": "HH-1, HH-2, HH-3, ", "individualIds": "IND-33, IND-33, ", "rules": []},
{"householdIds": "HH-1", "individualIds": "IND-33", "rules": []},
{"householdIds": "", "individualIds": "IND-33", "rules": []},
{"householdIds": "", "individualIds": "IND-33, IND-666", "rules": []},
{"householdIds": "", "individualIds": "IND-666", "rules": []},
{"householdIds": "HH-1, HH-666", "individualIds": "", "rules": []},
{"householdIds": "HH-666", "individualIds": "", "rules": []},
{"householdIds": "", "individualIds": "", "rules": []},
]

for num, targeting_criteria in enumerate(targeting_criteria_list, 1):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,54 +1,86 @@
from django.core.exceptions import ValidationError
from django.test import TestCase

from hct_mis_api.apps.core.fixtures import DataCollectingTypeFactory
from hct_mis_api.apps.core.fixtures import DataCollectingTypeFactory, create_afghanistan
from hct_mis_api.apps.core.models import DataCollectingType
from hct_mis_api.apps.household.fixtures import create_household
from hct_mis_api.apps.household.models import Household, Individual
from hct_mis_api.apps.program.fixtures import ProgramFactory
from hct_mis_api.apps.program.models import Program
from hct_mis_api.apps.targeting.validators import TargetingCriteriaInputValidator


class TestTargetingCriteriaInputValidator(TestCase):
@classmethod
def setUpTestData(cls) -> None:
cls.dct_standard = DataCollectingTypeFactory(
type=DataCollectingType.Type.STANDARD,
individual_filters_available=True,
household_filters_available=True,
create_afghanistan()
cls.program_standard = ProgramFactory(
data_collecting_type=DataCollectingTypeFactory(
type=DataCollectingType.Type.STANDARD,
individual_filters_available=True,
household_filters_available=True,
)
)
cls.dct_standard_hh_only = DataCollectingTypeFactory(
type=DataCollectingType.Type.STANDARD,
individual_filters_available=False,
household_filters_available=True,
cls.program_standard_hh_only = ProgramFactory(
data_collecting_type=DataCollectingTypeFactory(
type=DataCollectingType.Type.STANDARD,
individual_filters_available=False,
household_filters_available=True,
)
)
cls.dct_standard_ind_only = DataCollectingTypeFactory(
type=DataCollectingType.Type.STANDARD,
individual_filters_available=True,
household_filters_available=False,
cls.program_standard_ind_only = ProgramFactory(
data_collecting_type=DataCollectingTypeFactory(
type=DataCollectingType.Type.STANDARD,
individual_filters_available=True,
household_filters_available=False,
)
)
cls.dct_social = DataCollectingTypeFactory(
type=DataCollectingType.Type.SOCIAL,
individual_filters_available=True,
household_filters_available=False,
cls.program_social = ProgramFactory(
data_collecting_type=DataCollectingTypeFactory(
type=DataCollectingType.Type.SOCIAL,
individual_filters_available=True,
household_filters_available=False,
)
)

def test_TargetingCriteriaInputValidator(self) -> None:
validator = TargetingCriteriaInputValidator
create_household({"unicef_id": "HH-1", "size": 1}, {"unicef_id": "IND-1"})
with self.assertRaisesMessage(
ValidationError, "Target criteria can has only filters or ids, not possible to has both"
):
self._update_program(self.program_standard)
validator.validate(
{"rules": ["Rule1"], "household_ids": "HH-1", "individual_ids": "IND-1"}, self.dct_standard
{"rules": ["Rule1"], "household_ids": "HH-1", "individual_ids": "IND-1"}, self.program_standard
)

with self.assertRaisesMessage(ValidationError, "Target criteria can has only individual ids"):
validator.validate({"rules": [], "household_ids": "HH-1", "individual_ids": "IND-1"}, self.dct_social)
self._update_program(self.program_social)
validator.validate({"rules": [], "household_ids": "HH-1", "individual_ids": "IND-1"}, self.program_social)

self._update_program(self.program_standard_ind_only)
validator.validate(
{"rules": [], "household_ids": "HH-1", "individual_ids": "IND-1"}, self.dct_standard_ind_only
{"rules": [], "household_ids": "HH-1", "individual_ids": "IND-1"}, self.program_standard_ind_only
)

with self.assertRaisesMessage(ValidationError, "Target criteria can has only household ids"):
self._update_program(self.program_standard_hh_only)
validator.validate(
{"rules": [], "household_ids": "HH-1", "individual_ids": "IND-1"}, self.dct_standard_hh_only
{"rules": [], "household_ids": "HH-1", "individual_ids": "IND-1"}, self.program_standard_hh_only
)

with self.assertRaisesMessage(ValidationError, "There should be at least 1 rule in target criteria"):
validator.validate({"rules": [], "household_ids": "", "individual_ids": ""}, self.dct_standard_hh_only)
self._update_program(self.program_standard_hh_only)
validator.validate({"rules": [], "household_ids": "", "individual_ids": ""}, self.program_standard_hh_only)

with self.assertRaisesMessage(ValidationError, "The given households do not exist in the current program"):
self._update_program(self.program_standard)
validator.validate({"rules": [], "household_ids": "HH-666", "individual_ids": ""}, self.program_standard)

with self.assertRaisesMessage(ValidationError, "The given individuals do not exist in the current program"):
self._update_program(self.program_standard)
validator.validate({"rules": [], "household_ids": "", "individual_ids": "IND-666"}, self.program_standard)

def _update_program(self, program: Program) -> None:
Household.objects.all().update(program=program)
Individual.objects.all().update(program=program)
20 changes: 19 additions & 1 deletion backend/hct_mis_api/apps/targeting/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from hct_mis_api.apps.core.models import DataCollectingType, FlexibleAttribute
from hct_mis_api.apps.core.utils import get_attr_value
from hct_mis_api.apps.core.validators import BaseValidator
from hct_mis_api.apps.household.models import Household, Individual
from hct_mis_api.apps.program.models import Program
from hct_mis_api.apps.targeting.models import (
TargetingCriteriaRuleFilter,
Expand Down Expand Up @@ -135,7 +136,8 @@ def validate(rule: "Rule") -> None:

class TargetingCriteriaInputValidator:
@staticmethod
def validate(targeting_criteria: Dict, program_dct: DataCollectingType) -> None:
def validate(targeting_criteria: Dict, program: Program) -> None:
program_dct = program.data_collecting_type
rules = targeting_criteria.get("rules", [])
household_ids = targeting_criteria.get("household_ids")
individual_ids = targeting_criteria.get("individual_ids")
Expand All @@ -152,6 +154,22 @@ def validate(targeting_criteria: Dict, program_dct: DataCollectingType) -> None:
logger.error("Target criteria can has only household ids")
raise ValidationError("Target criteria can has only household ids")

if household_ids:
ids_list = household_ids.split(",")
ids_list = [i.strip() for i in ids_list]
ids_list = [i for i in ids_list if i.startswith("HH")]
if not Household.objects.filter(unicef_id__in=ids_list, program=program).exists():
logger.error("The given households do not exist in the current program")
raise ValidationError("The given households do not exist in the current program")

if individual_ids:
ids_list = individual_ids.split(",")
ids_list = [i.strip() for i in ids_list]
ids_list = [i for i in ids_list if i.startswith("IND")]
if not Individual.objects.filter(unicef_id__in=ids_list, program=program).exists():
logger.error("The given individuals do not exist in the current program")
raise ValidationError("The given individuals do not exist in the current program")

if len(rules) < 1 and not household_ids and not individual_ids:
logger.error("There should be at least 1 rule in target criteria")
raise ValidationError("There should be at least 1 rule in target criteria")
Expand Down
10 changes: 8 additions & 2 deletions backend/selenium_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from page_object.payment_module.new_payment_plan import NewPaymentPlan
from page_object.payment_module.payment_module import PaymentModule
from page_object.payment_module.payment_module_details import PaymentModuleDetails
from page_object.payment_verification.payment_record import PaymentRecord
from page_object.payment_verification.payment_verification import PaymentVerification
from page_object.payment_verification.payment_verification_details import (
PaymentVerificationDetails,
Expand Down Expand Up @@ -292,15 +293,20 @@ def pagePaymentModule(request: FixtureRequest, browser: Chrome) -> PaymentModule


@pytest.fixture
def pagePaymentVerification(request: FixtureRequest, browser: Chrome) -> PaymentVerification:
yield PaymentVerification(browser)
def pagePaymentRecord(request: FixtureRequest, browser: Chrome) -> PaymentRecord:
yield PaymentRecord(browser)


@pytest.fixture
def pagePaymentVerificationDetails(request: FixtureRequest, browser: Chrome) -> PaymentVerificationDetails:
yield PaymentVerificationDetails(browser)


@pytest.fixture
def pagePaymentVerification(request: FixtureRequest, browser: Chrome) -> PaymentVerification:
yield PaymentVerification(browser)


@pytest.fixture
def pageTargetingDetails(request: FixtureRequest, browser: Chrome) -> TargetingDetails:
yield TargetingDetails(browser)
Expand Down
8 changes: 8 additions & 0 deletions backend/selenium_tests/page_object/base_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class BaseComponents(Common):
globalProgramFilterSearchButton = 'button[data-cy="search-icon"]'
globalProgramFilterClearButton = 'button[data-cy="clear-icon"]'
rows = 'tr[role="checkbox"]'
breadcrumbsChevronIcon = 'svg[data-cy="breadcrumbs-chevron-icon"]'
arrowBack = 'div[data-cy="arrow_back"]'

# Text
globalProgramFilterText = "All Programmes"
Expand Down Expand Up @@ -174,6 +176,12 @@ def getGlobalProgramFilterSearchButton(self) -> WebElement:
def getGlobalProgramFilterSearchInput(self) -> WebElement:
return self.wait_for(self.globalProgramFilterSearchInput)

def getBreadcrumbsChevronIcon(self) -> WebElement:
return self.wait_for(self.breadcrumbsChevronIcon)

def getArrowBack(self) -> WebElement:
return self.wait_for(self.arrowBack)

def getNavProgramLog(self) -> WebElement:
return self.wait_for(self.navProgramLog)

Expand Down
Loading

0 comments on commit 0833860

Please sign in to comment.