unit tests

This commit is contained in:
Rachid Mrad 2024-07-17 21:04:59 -04:00
parent 72ee81a43c
commit ea6ccae948
No known key found for this signature in database
7 changed files with 309 additions and 43 deletions

View file

@ -296,6 +296,8 @@ function openInNewTab(el, removeAttribute = false){
// "to" select list // "to" select list
checkToListThenInitWidget('id_groups_to', 0); checkToListThenInitWidget('id_groups_to', 0);
checkToListThenInitWidget('id_user_permissions_to', 0); checkToListThenInitWidget('id_user_permissions_to', 0);
checkToListThenInitWidget('id_portfolio_roles_to', 0);
checkToListThenInitWidget('id_portfolio_additional_permissions_to', 0);
})(); })();
// Function to check for the existence of the "to" select list element in the DOM, and if and when found, // Function to check for the existence of the "to" select list element in the DOM, and if and when found,

View file

@ -34,22 +34,6 @@
pointer-events: none; pointer-events: none;
} }
} }
// Ticket #1510
// @include at-media('desktop') {
// th:first-child {
// width: 220px;
// }
// th:nth-child(2) {
// width: 175px;
// }
// th:nth-child(3) {
// width: 130px;
// }
// th:nth-child(5) {
// width: 130px;
// }
// }
} }
.dotgov-table { .dotgov-table {

View file

@ -138,7 +138,7 @@ class User(AbstractUser):
null=True, null=True,
blank=True, blank=True,
related_name="user", related_name="user",
on_delete=models.PROTECT, on_delete=models.SET_NULL,
) )
portfolio_roles = ArrayField( portfolio_roles = ArrayField(
@ -250,35 +250,35 @@ class User(AbstractUser):
def has_contact_info(self): def has_contact_info(self):
return bool(self.title or self.email or self.phone) return bool(self.title or self.email or self.phone)
def has_role(self, role):
"""Do not rely on roles when testing for perms in views"""
return role in self.portfolio_roles if self.portfolio_roles else False
def has_portfolio_permission(self, portfolio_permission): def has_portfolio_permission(self, portfolio_permission):
"""The views should only call this guy when testing for perms and not rely on roles""" """The views should only call this guy when testing for perms and not rely on roles"""
print(f"IN has_portfolio_permission")
# EDIT_DOMAINS === user is a manager on a domain (has UserDomainRole) # EDIT_DOMAINS === user is a manager on a domain (has UserDomainRole)
# NOTE: Should we check whether the domain is in the portfolio? # NOTE: Should we check whether the domain is in the portfolio?
if portfolio_permission == self.UserPortfolioPermissionChoices.EDIT_DOMAINS and self.domains.exists(): if portfolio_permission == self.UserPortfolioPermissionChoices.EDIT_DOMAINS and self.domains.exists():
return True return True
if not self.portfolio: if not self.portfolio:
return False return False
portfolio_permissions = self.get_portfolio_permissions() portfolio_permissions = self._get_portfolio_permissions()
return portfolio_permission in portfolio_permissions return portfolio_permission in portfolio_permissions
def get_portfolio_permissions(self): def _get_portfolio_permissions(self):
""" """
Retrieve the permissions for the user's portfolio roles. Retrieve the permissions for the user's portfolio roles.
""" """
portfolio_permissions = set() # Use a set to avoid duplicate permissions portfolio_permissions = set() # Use a set to avoid duplicate permissions
for role in self.portfolio_roles: if self.portfolio_roles:
if role in self.PORTFOLIO_ROLE_PERMISSIONS: for role in self.portfolio_roles:
portfolio_permissions.update(self.PORTFOLIO_ROLE_PERMISSIONS[role]) if role in self.PORTFOLIO_ROLE_PERMISSIONS:
portfolio_permissions.update(self.portfolio_additional_permissions) portfolio_permissions.update(self.PORTFOLIO_ROLE_PERMISSIONS[role])
if self.portfolio_additional_permissions:
portfolio_permissions.update(self.portfolio_additional_permissions)
return list(portfolio_permissions) # Convert back to list if necessary return list(portfolio_permissions) # Convert back to list if necessary
@classmethod @classmethod

View file

@ -3710,6 +3710,22 @@ class TestMyUserAdmin(MockDb):
expected_href = reverse("admin:registrar_domain_change", args=[domain_deleted.pk]) expected_href = reverse("admin:registrar_domain_change", args=[domain_deleted.pk])
self.assertNotContains(response, expected_href) self.assertNotContains(response, expected_href)
def test_analyst_can_see_selects_for_portfolio_role_and_permissions_in_user_form(self):
"""Can only test for the presence of a base element. The multiselects and the h2->h3 conversion are all
dynamically generated."""
p = "userpass"
self.client.login(username="staffuser", password=p)
response = self.client.get(
"/admin/registrar/user/{}/change/".format(self.meoward_user.id),
follow=True,
)
self.assertEqual(response.status_code, 200)
self.assertContains(response,"Portfolio roles:")
self.assertContains(response,"Portfolio additional permissions:")
class AuditedAdminTest(TestCase): class AuditedAdminTest(TestCase):
def setUp(self): def setUp(self):

View file

@ -19,6 +19,7 @@ from registrar.models import (
) )
import boto3_mocking import boto3_mocking
from registrar.models.portfolio import Portfolio
from registrar.models.transition_domain import TransitionDomain from registrar.models.transition_domain import TransitionDomain
from registrar.models.verified_by_staff import VerifiedByStaff # type: ignore from registrar.models.verified_by_staff import VerifiedByStaff # type: ignore
from registrar.utility.constants import BranchChoices from registrar.utility.constants import BranchChoices
@ -1214,6 +1215,66 @@ class TestUser(TestCase):
self.user.phone = None self.user.phone = None
self.assertFalse(self.user.has_contact_info()) self.assertFalse(self.user.has_contact_info())
def test_has_portfolio_permission(self):
"""
0. Returns False when user does not have a permission
1. Returns False when a user does not have a portfolio
2. Returns True when user has direct permission
3. Returns True when user has permission through a role
4. Returns True EDIT_DOMAINS when user does not have the perm but has UserDomainRole
Note: This tests _get_portfolio_permissions as a side effect
"""
portfolio, _ = Portfolio.objects.get_or_create(creator=self.user, organization_name="Hotel California")
self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_DOMAINS]
self.user.save()
self.user.refresh_from_db()
user_can_view_domains = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_DOMAINS)
user_can_view_requests = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_REQUESTS)
user_can_edit_domains = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.EDIT_DOMAINS)
self.assertFalse(user_can_view_domains)
self.assertFalse(user_can_view_requests)
self.assertFalse(user_can_edit_domains)
self.user.portfolio=portfolio
self.user.save()
self.user.refresh_from_db()
user_can_view_domains = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_DOMAINS)
user_can_view_requests = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_REQUESTS)
user_can_edit_domains = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.EDIT_DOMAINS)
self.assertTrue(user_can_view_domains)
self.assertFalse(user_can_view_requests)
self.assertFalse(user_can_edit_domains)
self.user.portfolio_roles = [User.UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
self.user.save()
self.user.refresh_from_db()
user_can_view_domains = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_DOMAINS)
user_can_view_requests = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_REQUESTS)
user_can_edit_domains = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.EDIT_DOMAINS)
self.assertTrue(user_can_view_domains)
self.assertTrue(user_can_view_requests)
self.assertFalse(user_can_edit_domains)
UserDomainRole.objects.all().get_or_create(user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER)
user_can_view_domains = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_DOMAINS)
user_can_view_requests = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_REQUESTS)
user_can_edit_domains = self.user.has_portfolio_permission(User.UserPortfolioPermissionChoices.EDIT_DOMAINS)
self.assertTrue(user_can_view_domains)
self.assertTrue(user_can_view_requests)
self.assertTrue(user_can_edit_domains)
Portfolio.objects.all().delete()
class TestContact(TestCase): class TestContact(TestCase):
def setUp(self): def setUp(self):

View file

@ -958,22 +958,22 @@ class PortfoliosTests(TestWithUser, WebTest):
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
@less_console_noise_decorator # @less_console_noise_decorator
def test_middleware_redirects_to_portfolio_homepage(self): # def test_middleware_redirects_to_portfolio_homepage(self):
"""Tests that a user is redirected to the portfolio homepage when organization_feature is on and # """Tests that a user is redirected to the portfolio homepage when organization_feature is on and
a portfolio belongs to the user, test for the special h1s which only exist in that version # a portfolio belongs to the user, test for the special h1s which only exist in that version
of the homepage""" # of the homepage"""
self.app.set_user(self.user.username) # self.app.set_user(self.user.username)
with override_flag("organization_feature", active=True): # with override_flag("organization_feature", active=True):
# This will redirect the user to the portfolio page. # # This will redirect the user to the portfolio page.
# Follow implicity checks if our redirect is working. # # Follow implicity checks if our redirect is working.
portfolio_page = self.app.get(reverse("home")).follow() # portfolio_page = self.app.get(reverse("home")).follow()
self._set_session_cookie() # self._set_session_cookie()
# Assert that we're on the right page # # Assert that we're on the right page
self.assertContains(portfolio_page, self.portfolio.organization_name) # self.assertContains(portfolio_page, self.portfolio.organization_name)
self.assertContains(portfolio_page, '<h1 id="domains-header">Domains</h1>') # self.assertContains(portfolio_page, '<h1 id="domains-header">Domains</h1>')
@less_console_noise_decorator @less_console_noise_decorator
def test_no_redirect_when_org_flag_false(self): def test_no_redirect_when_org_flag_false(self):

View file

@ -0,0 +1,203 @@
from unittest import skip
from unittest.mock import MagicMock, ANY, patch
from django.conf import settings
from django.urls import reverse
from django.contrib.auth import get_user_model
from api.tests.common import less_console_noise_decorator
from registrar.models.portfolio import Portfolio
from .common import MockEppLib, MockSESClient, create_user # type: ignore
from django_webtest import WebTest # type: ignore
import boto3_mocking # type: ignore
from registrar.utility.errors import (
NameserverError,
NameserverErrorCodes,
SecurityEmailError,
SecurityEmailErrorCodes,
GenericError,
GenericErrorCodes,
DsDataError,
DsDataErrorCodes,
)
from registrar.models import (
DomainRequest,
Domain,
DomainInformation,
DomainInvitation,
Contact,
PublicContact,
Host,
HostIP,
UserDomainRole,
User,
FederalAgency,
)
from datetime import date, datetime, timedelta
from django.utils import timezone
from .common import less_console_noise
from .test_views import TestWithUser
from waffle.testutils import override_flag
import logging
logger = logging.getLogger(__name__)
class TestPortfolioViews(TestWithUser, WebTest):
def setUp(self):
super().setUp()
self.domain, _ = Domain.objects.get_or_create(name="igorville.gov")
self.portfolio, _ = Portfolio.objects.get_or_create(creator=self.user, organization_name="Hotel California")
self.role, _ = UserDomainRole.objects.get_or_create(
user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER
)
@less_console_noise_decorator
def test_middleware_does_not_redirect_if_no_permission(self):
""""""
self.app.set_user(self.user.username)
self.user.portfolio=self.portfolio
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
# This will redirect the user to the portfolio page.
# Follow implicity checks if our redirect is working.
portfolio_page = self.app.get(reverse("home"))
# Assert that we're on the right page
self.assertNotContains(portfolio_page, self.portfolio.organization_name)
@less_console_noise_decorator
def test_middleware_does_not_redirect_if_no_portfolio(self):
""" """
self.app.set_user(self.user.username)
self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
# This will redirect the user to the portfolio page.
# Follow implicity checks if our redirect is working.
portfolio_page = self.app.get(reverse("home"))
# Assert that we're on the right page
self.assertNotContains(portfolio_page, self.portfolio.organization_name)
@less_console_noise_decorator
def test_middleware_redirects_to_portfolio_organization_page(self):
""""""
self.app.set_user(self.user.username)
self.user.portfolio=self.portfolio
self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
# This will redirect the user to the portfolio page.
# Follow implicity checks if our redirect is working.
portfolio_page = self.app.get(reverse("home")).follow()
# Assert that we're on the right page
self.assertContains(portfolio_page, self.portfolio.organization_name)
self.assertContains(portfolio_page, '<h1>Organization</h1>')
@less_console_noise_decorator
def test_middleware_redirects_to_portfolio_domains_page(self):
""""""
self.app.set_user(self.user.username)
self.user.portfolio=self.portfolio
self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO, User.UserPortfolioPermissionChoices.VIEW_DOMAINS]
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
# This will redirect the user to the portfolio page.
# Follow implicity checks if our redirect is working.
portfolio_page = self.app.get(reverse("home")).follow()
# Assert that we're on the right page
self.assertContains(portfolio_page, self.portfolio.organization_name)
self.assertNotContains(portfolio_page, '<h1>Organization</h1>')
self.assertContains(portfolio_page, '<h1 id="domains-header">Domains</h1>')
@less_console_noise_decorator
def test_portfolio_domains_page_403_when_user_not_have_permission(self):
""""""
self.app.set_user(self.user.username)
self.user.portfolio=self.portfolio
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
# This will redirect the user to the portfolio page.
# Follow implicity checks if our redirect is working.
response = self.app.get(reverse("portfolio-domains", kwargs={"portfolio_id": self.portfolio.pk}), status=403)
# Assert the response is a 403
# Assert the response is a 403 Forbidden
self.assertEqual(response.status_code, 403)
@less_console_noise_decorator
def test_portfolio_domain_requests_page_403_when_user_not_have_permission(self):
""""""
self.app.set_user(self.user.username)
self.user.portfolio=self.portfolio
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
# This will redirect the user to the portfolio page.
# Follow implicity checks if our redirect is working.
response = self.app.get(reverse("portfolio-domain-requests", kwargs={"portfolio_id": self.portfolio.pk}), status=403)
# Assert the response is a 403
# Assert the response is a 403 Forbidden
self.assertEqual(response.status_code, 403)
@less_console_noise_decorator
def test_portfolio_organization_page_403_when_user_not_have_permission(self):
""""""
self.app.set_user(self.user.username)
self.user.portfolio=self.portfolio
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
# This will redirect the user to the portfolio page.
# Follow implicity checks if our redirect is working.
response = self.app.get(reverse("portfolio-organization", kwargs={"portfolio_id": self.portfolio.pk}), status=403)
# Assert the response is a 403
# Assert the response is a 403 Forbidden
self.assertEqual(response.status_code, 403)
@less_console_noise_decorator
def test_navigation_links_hidden_when_user_not_have_permission(self):
"""This test is AMAZING"""
self.app.set_user(self.user.username)
self.user.portfolio=self.portfolio
self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO, User.UserPortfolioPermissionChoices.VIEW_DOMAINS, User.UserPortfolioPermissionChoices.VIEW_REQUESTS]
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
# This will redirect the user to the portfolio page.
# Follow implicity checks if our redirect is working.
portfolio_page = self.app.get(reverse("home")).follow()
# Assert that we're on the right page
self.assertContains(portfolio_page, self.portfolio.organization_name)
self.assertNotContains(portfolio_page, '<h1>Organization</h1>')
self.assertContains(portfolio_page, '<h1 id="domains-header">Domains</h1>')
self.assertContains(portfolio_page, reverse("portfolio-domains", kwargs={"portfolio_id": self.portfolio.pk}))
self.assertContains(portfolio_page, reverse("portfolio-domain-requests", kwargs={"portfolio_id": self.portfolio.pk}))
self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
self.user.save()
self.user.refresh_from_db()
portfolio_page = self.app.get(reverse("home")).follow()
self.assertContains(portfolio_page, self.portfolio.organization_name)
self.assertContains(portfolio_page, '<h1>Organization</h1>')
self.assertNotContains(portfolio_page, '<h1 id="domains-header">Domains</h1>')
self.assertNotContains(portfolio_page, reverse("portfolio-domains", kwargs={"portfolio_id": self.portfolio.pk}))
self.assertNotContains(portfolio_page, reverse("portfolio-domain-requests", kwargs={"portfolio_id": self.portfolio.pk}))
def tearDown(self):
Portfolio.objects.all().delete()
UserDomainRole.objects.all().delete()
DomainRequest.objects.all().delete()
DomainInformation.objects.all().delete()
Domain.objects.all().delete()
super().tearDown()