domain manager tests and linted

This commit is contained in:
David Kennedy 2024-12-20 20:29:21 -05:00
parent f2bd0ad8b0
commit d36e2e2a63
No known key found for this signature in database
GPG key ID: 6528A5386E66B96B
5 changed files with 218 additions and 51 deletions

View file

@ -710,7 +710,6 @@ class TestPortfolioInvitationAdmin(TestCase):
# self.assertContains(response, "Simulated error message", msg_prefix="Expected error message not found.") # self.assertContains(response, "Simulated error message", msg_prefix="Expected error message not found.")
class TestHostAdmin(TestCase): class TestHostAdmin(TestCase):
"""Tests for the HostAdmin class as super user """Tests for the HostAdmin class as super user

View file

@ -18,7 +18,11 @@ from registrar.forms.domain_request_wizard import (
AboutYourOrganizationForm, AboutYourOrganizationForm,
) )
from registrar.forms.domain import ContactForm from registrar.forms.domain import ContactForm
from registrar.forms.portfolio import BasePortfolioMemberForm, PortfolioInvitedMemberForm, PortfolioMemberForm, PortfolioNewMemberForm from registrar.forms.portfolio import (
PortfolioInvitedMemberForm,
PortfolioMemberForm,
PortfolioNewMemberForm,
)
from registrar.models.portfolio import Portfolio from registrar.models.portfolio import Portfolio
from registrar.models.portfolio_invitation import PortfolioInvitation from registrar.models.portfolio_invitation import PortfolioInvitation
from registrar.models.user import User from registrar.models.user import User
@ -423,7 +427,9 @@ class TestBasePortfolioMemberForms(TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.user = create_user() self.user = create_user()
self.portfolio, _ = Portfolio.objects.get_or_create(creator_id=self.user.id, organization_name="Hotel California") self.portfolio, _ = Portfolio.objects.get_or_create(
creator_id=self.user.id, organization_name="Hotel California"
)
def tearDown(self): def tearDown(self):
super().tearDown() super().tearDown()
@ -433,10 +439,10 @@ class TestBasePortfolioMemberForms(TestCase):
User.objects.all().delete() User.objects.all().delete()
def _assert_form_is_valid(self, form_class, data, instance=None): def _assert_form_is_valid(self, form_class, data, instance=None):
if instance != None: if instance is not None:
form = form_class(data=data, instance=instance) form = form_class(data=data, instance=instance)
else: else:
print('no instance') print("no instance")
form = form_class(data=data) form = form_class(data=data)
self.assertTrue(form.is_valid(), f"Form {form_class.__name__} failed validation with data: {data}") self.assertTrue(form.is_valid(), f"Form {form_class.__name__} failed validation with data: {data}")
return form return form
@ -491,13 +497,15 @@ class TestBasePortfolioMemberForms(TestCase):
def test_clean_validates_required_fields_for_role(self): def test_clean_validates_required_fields_for_role(self):
"""Test that the `clean` method validates the correct fields for each role. """Test that the `clean` method validates the correct fields for each role.
For PortfolioMemberForm and PortfolioInvitedMemberForm, we pass an object as the instance to the form. For PortfolioMemberForm and PortfolioInvitedMemberForm, we pass an object as the instance to the form.
For UserPortfolioPermissionChoices, we add a portfolio and an email to the POST data. For UserPortfolioPermissionChoices, we add a portfolio and an email to the POST data.
These things are handled in the views.""" These things are handled in the views."""
user_portfolio_permission, _ = UserPortfolioPermission.objects.get_or_create(portfolio=self.portfolio, user=self.user) user_portfolio_permission, _ = UserPortfolioPermission.objects.get_or_create(
portfolio=self.portfolio, user=self.user
)
portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(portfolio=self.portfolio, email="hi@ho") portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(portfolio=self.portfolio, email="hi@ho")
data = { data = {
@ -519,7 +527,7 @@ class TestBasePortfolioMemberForms(TestCase):
data = { data = {
"email": "hi@ho.com", "email": "hi@ho.com",
"portfolio": self.portfolio.id, "portfolio": self.portfolio.id,
"role": UserPortfolioRoleChoices.ORGANIZATION_ADMIN.value, "role": UserPortfolioRoleChoices.ORGANIZATION_ADMIN.value,
"domain_request_permission_admin": UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value, "domain_request_permission_admin": UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value,
"member_permission_admin": UserPortfolioPermissionChoices.EDIT_MEMBERS.value, "member_permission_admin": UserPortfolioPermissionChoices.EDIT_MEMBERS.value,
@ -534,7 +542,9 @@ class TestBasePortfolioMemberForms(TestCase):
"""Test that the clean method correctly handles the special "no_access" value for members. """Test that the clean method correctly handles the special "no_access" value for members.
We'll need to add a portfolio, which in the app is handled by the view post.""" We'll need to add a portfolio, which in the app is handled by the view post."""
user_portfolio_permission, _ = UserPortfolioPermission.objects.get_or_create(portfolio=self.portfolio, user=self.user) user_portfolio_permission, _ = UserPortfolioPermission.objects.get_or_create(
portfolio=self.portfolio, user=self.user
)
portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(portfolio=self.portfolio, email="hi@ho") portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(portfolio=self.portfolio, email="hi@ho")
data = { data = {
@ -550,7 +560,6 @@ class TestBasePortfolioMemberForms(TestCase):
cleaned_data = form.cleaned_data cleaned_data = form.cleaned_data
self.assertEqual(cleaned_data["domain_request_permission_member"], None) self.assertEqual(cleaned_data["domain_request_permission_member"], None)
def test_map_instance_to_initial_admin_role(self): def test_map_instance_to_initial_admin_role(self):
"""Test that instance data is correctly mapped to the initial form values for an admin role.""" """Test that instance data is correctly mapped to the initial form values for an admin role."""
user_portfolio_permission = UserPortfolioPermission( user_portfolio_permission = UserPortfolioPermission(
@ -558,7 +567,7 @@ class TestBasePortfolioMemberForms(TestCase):
additional_permissions=[UserPortfolioPermissionChoices.VIEW_MEMBERS], additional_permissions=[UserPortfolioPermissionChoices.VIEW_MEMBERS],
) )
portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create( portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(
portfolio=self.portfolio, portfolio=self.portfolio,
email="hi@ho", email="hi@ho",
roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN], roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN],
additional_permissions=[UserPortfolioPermissionChoices.VIEW_MEMBERS], additional_permissions=[UserPortfolioPermissionChoices.VIEW_MEMBERS],
@ -579,7 +588,7 @@ class TestBasePortfolioMemberForms(TestCase):
additional_permissions=[UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS], additional_permissions=[UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS],
) )
portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create( portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(
portfolio=self.portfolio, portfolio=self.portfolio,
email="hi@ho", email="hi@ho",
roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER], roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER],
additional_permissions=[UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS], additional_permissions=[UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS],
@ -595,7 +604,7 @@ class TestBasePortfolioMemberForms(TestCase):
"""Test invalid form submission for an admin role with missing permissions.""" """Test invalid form submission for an admin role with missing permissions."""
data = { data = {
"email": "hi@ho.com", "email": "hi@ho.com",
"portfolio": self.portfolio.id, "portfolio": self.portfolio.id,
"role": UserPortfolioRoleChoices.ORGANIZATION_ADMIN.value, "role": UserPortfolioRoleChoices.ORGANIZATION_ADMIN.value,
"domain_request_permission_admin": "", # Missing field "domain_request_permission_admin": "", # Missing field
"member_permission_admin": "", # Missing field "member_permission_admin": "", # Missing field

View file

@ -4,6 +4,8 @@ from unittest.mock import MagicMock, ANY, patch
from django.conf import settings from django.conf import settings
from django.urls import reverse from django.urls import reverse
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from registrar.models.portfolio_invitation import PortfolioInvitation
from registrar.utility.email import EmailSendingError
from waffle.testutils import override_flag from waffle.testutils import override_flag
from api.tests.common import less_console_noise_decorator from api.tests.common import less_console_noise_decorator
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
@ -454,6 +456,7 @@ class TestDomainManagers(TestDomainOverview):
def tearDown(self): def tearDown(self):
"""Ensure that the user has its original permissions""" """Ensure that the user has its original permissions"""
PortfolioInvitation.objects.all().delete()
super().tearDown() super().tearDown()
@less_console_noise_decorator @less_console_noise_decorator
@ -486,7 +489,7 @@ class TestDomainManagers(TestDomainOverview):
@less_console_noise_decorator @less_console_noise_decorator
def test_domain_user_add_form(self): def test_domain_user_add_form(self):
"""Adding an existing user works.""" """Adding an existing user works."""
other_user, _ = get_user_model().objects.get_or_create(email="mayor@igorville.gov") get_user_model().objects.get_or_create(email="mayor@igorville.gov")
add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id})) add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
@ -509,6 +512,148 @@ class TestDomainManagers(TestDomainOverview):
success_page = success_result.follow() success_page = success_result.follow()
self.assertContains(success_page, "mayor@igorville.gov") self.assertContains(success_page, "mayor@igorville.gov")
@boto3_mocking.patching
@override_flag("organization_feature", active=True)
@less_console_noise_decorator
@patch("registrar.views.domain.send_portfolio_invitation_email")
@patch("registrar.views.domain.send_domain_invitation_email")
def test_domain_user_add_form_sends_portfolio_invitation(self, mock_send_domain_email, mock_send_portfolio_email):
"""Adding an existing user works and sends portfolio invitation when
user is not member of portfolio."""
get_user_model().objects.get_or_create(email="mayor@igorville.gov")
add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
add_page.form["email"] = "mayor@igorville.gov"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
success_result = add_page.form.submit()
self.assertEqual(success_result.status_code, 302)
self.assertEqual(
success_result["Location"],
reverse("domain-users", kwargs={"pk": self.domain.id}),
)
# Verify that the invitation emails were sent
mock_send_portfolio_email.assert_called_once_with(
email="mayor@igorville.gov", requestor=self.user, portfolio=self.portfolio
)
mock_send_domain_email.assert_called_once()
call_args = mock_send_domain_email.call_args.kwargs
self.assertEqual(call_args["email"], "mayor@igorville.gov")
self.assertEqual(call_args["requestor"], self.user)
self.assertEqual(call_args["domain"], self.domain)
self.assertIsNone(call_args.get("is_member_of_different_org"))
# Assert that the PortfolioInvitation is created
portfolio_invitation = PortfolioInvitation.objects.filter(
email="mayor@igorville.gov", portfolio=self.portfolio
).first()
self.assertIsNotNone(portfolio_invitation, "Portfolio invitation should be created.")
self.assertEqual(portfolio_invitation.email, "mayor@igorville.gov")
self.assertEqual(portfolio_invitation.portfolio, self.portfolio)
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
success_page = success_result.follow()
self.assertContains(success_page, "mayor@igorville.gov")
@boto3_mocking.patching
@override_flag("organization_feature", active=True)
@less_console_noise_decorator
@patch("registrar.views.domain.send_portfolio_invitation_email")
@patch("registrar.views.domain.send_domain_invitation_email")
def test_domain_user_add_form_doesnt_send_portfolio_invitation_if_already_member(
self, mock_send_domain_email, mock_send_portfolio_email
):
"""Adding an existing user works and sends portfolio invitation when
user is not member of portfolio."""
other_user, _ = get_user_model().objects.get_or_create(email="mayor@igorville.gov")
UserPortfolioPermission.objects.get_or_create(
user=other_user, portfolio=self.portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
)
add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
add_page.form["email"] = "mayor@igorville.gov"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
success_result = add_page.form.submit()
self.assertEqual(success_result.status_code, 302)
self.assertEqual(
success_result["Location"],
reverse("domain-users", kwargs={"pk": self.domain.id}),
)
# Verify that the invitation emails were sent
mock_send_portfolio_email.assert_not_called()
mock_send_domain_email.assert_called_once()
call_args = mock_send_domain_email.call_args.kwargs
self.assertEqual(call_args["email"], "mayor@igorville.gov")
self.assertEqual(call_args["requestor"], self.user)
self.assertEqual(call_args["domain"], self.domain)
self.assertIsNone(call_args.get("is_member_of_different_org"))
# Assert that no PortfolioInvitation is created
portfolio_invitation_exists = PortfolioInvitation.objects.filter(
email="mayor@igorville.gov", portfolio=self.portfolio
).exists()
self.assertFalse(
portfolio_invitation_exists, "Portfolio invitation should not be created when the user is already a member."
)
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
success_page = success_result.follow()
self.assertContains(success_page, "mayor@igorville.gov")
@boto3_mocking.patching
@override_flag("organization_feature", active=True)
@less_console_noise_decorator
@patch("registrar.views.domain.send_portfolio_invitation_email")
@patch("registrar.views.domain.send_domain_invitation_email")
def test_domain_user_add_form_sends_portfolio_invitation_raises_email_sending_error(
self, mock_send_domain_email, mock_send_portfolio_email
):
"""Adding an existing user works and attempts to send portfolio invitation when
user is not member of portfolio and send raises an error."""
mock_send_portfolio_email.side_effect = EmailSendingError("Failed to send email.")
get_user_model().objects.get_or_create(email="mayor@igorville.gov")
add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
add_page.form["email"] = "mayor@igorville.gov"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
success_result = add_page.form.submit()
self.assertEqual(success_result.status_code, 302)
self.assertEqual(
success_result["Location"],
reverse("domain-users", kwargs={"pk": self.domain.id}),
)
# Verify that the invitation emails were sent
mock_send_portfolio_email.assert_called_once_with(
email="mayor@igorville.gov", requestor=self.user, portfolio=self.portfolio
)
mock_send_domain_email.assert_not_called()
# Assert that no PortfolioInvitation is created
portfolio_invitation_exists = PortfolioInvitation.objects.filter(
email="mayor@igorville.gov", portfolio=self.portfolio
).exists()
self.assertFalse(
portfolio_invitation_exists, "Portfolio invitation should not be created when email fails to send."
)
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
success_page = success_result.follow()
self.assertContains(success_page, "Could not send email invitation.")
@boto3_mocking.patching @boto3_mocking.patching
@less_console_noise_decorator @less_console_noise_decorator
def test_domain_invitation_created(self): def test_domain_invitation_created(self):
@ -757,7 +902,9 @@ class TestDomainManagers(TestDomainOverview):
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
add_page.form.submit() add_page.form.submit()
expected_message_content = f"Can't send invitation email. No email is associated with the account for 'test_user'." expected_message_content = (
"Can't send invitation email. No email is associated with the account for 'test_user'."
)
# Assert that the error message was called with the correct argument # Assert that the error message was called with the correct argument
mock_error.assert_called_once_with( mock_error.assert_called_once_with(

View file

@ -20,7 +20,6 @@ from registrar.models.user_portfolio_permission import UserPortfolioPermission
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
from registrar.tests.test_views import TestWithUser from registrar.tests.test_views import TestWithUser
from registrar.utility.email import EmailSendingError from registrar.utility.email import EmailSendingError
from registrar.utility.email_invitations import send_portfolio_invitation_email
from registrar.utility.errors import MissingEmailError from registrar.utility.errors import MissingEmailError
from .common import MockSESClient, completed_domain_request, create_test_user, create_user from .common import MockSESClient, completed_domain_request, create_test_user, create_user
from waffle.testutils import override_flag from waffle.testutils import override_flag
@ -2585,7 +2584,7 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
) )
# Ensure the final submission is successful # Ensure the final submission is successful
self.assertEqual(final_response.status_code, 302) # Redirects self.assertEqual(final_response.status_code, 302) # Redirects
# Validate Database Changes # Validate Database Changes
portfolio_invite = PortfolioInvitation.objects.filter( portfolio_invite = PortfolioInvitation.objects.filter(
@ -2611,7 +2610,7 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
mock_client_class = MagicMock() mock_client_class = MagicMock()
mock_client = mock_client_class.return_value mock_client = mock_client_class.return_value
with boto3_mocking.clients.handler_for("sesv2", mock_client_class): with boto3_mocking.clients.handler_for("sesv2", mock_client_class):
# Simulate submission of member invite for new user # Simulate submission of member invite for new user
final_response = self.client.post( final_response = self.client.post(
@ -2635,7 +2634,7 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
# assert that portfolio invitation is not created # assert that portfolio invitation is not created
self.assertFalse( self.assertFalse(
PortfolioInvitation.objects.filter(email=self.new_member_email, portfolio=self.portfolio).exists(), PortfolioInvitation.objects.filter(email=self.new_member_email, portfolio=self.portfolio).exists(),
"Portfolio invitation should not be created when an Exception occurs." "Portfolio invitation should not be created when an Exception occurs.",
) )
# Check that an email was not sent # Check that an email was not sent
@ -2671,7 +2670,7 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
json_response = response.json() json_response = response.json()
self.assertIn("is_valid", json_response) self.assertIn("is_valid", json_response)
self.assertFalse(json_response["is_valid"]) self.assertFalse(json_response["is_valid"])
# Validate Database has not changed # Validate Database has not changed
invite_count_after = PortfolioInvitation.objects.count() invite_count_after = PortfolioInvitation.objects.count()
self.assertEqual(invite_count_after, invite_count_before) self.assertEqual(invite_count_after, invite_count_before)
@ -2686,9 +2685,9 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
def test_submit_new_member_raises_email_sending_error(self, mock_send_email): def test_submit_new_member_raises_email_sending_error(self, mock_send_email):
"""Test when adding a new member and email_send method raises EmailSendingError.""" """Test when adding a new member and email_send method raises EmailSendingError."""
mock_send_email.side_effect = EmailSendingError("Failed to send email.") mock_send_email.side_effect = EmailSendingError("Failed to send email.")
self.client.force_login(self.user) self.client.force_login(self.user)
# Simulate a session to ensure continuity # Simulate a session to ensure continuity
session_id = self.client.session.session_key session_id = self.client.session.session_key
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
@ -2698,11 +2697,11 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
"domain_request_permission_member": UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value, "domain_request_permission_member": UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value,
"email": self.new_member_email, "email": self.new_member_email,
} }
# Act # Act
with patch("django.contrib.messages.warning") as mock_warning: with patch("django.contrib.messages.warning") as mock_warning:
response = self.client.post(reverse("new-member"), data=form_data) response = self.client.post(reverse("new-member"), data=form_data)
# Assert # Assert
# assert that the send_portfolio_invitation_email called # assert that the send_portfolio_invitation_email called
mock_send_email.assert_called_once_with( mock_send_email.assert_called_once_with(
@ -2711,13 +2710,11 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
# assert that response is a redirect to reverse("members") # assert that response is a redirect to reverse("members")
self.assertRedirects(response, reverse("members")) self.assertRedirects(response, reverse("members"))
# assert that messages contains message, "Could not send email invitation" # assert that messages contains message, "Could not send email invitation"
mock_warning.assert_called_once_with( mock_warning.assert_called_once_with(response.wsgi_request, "Could not send email invitation.")
response.wsgi_request, "Could not send email invitation."
)
# assert that portfolio invitation is not created # assert that portfolio invitation is not created
self.assertFalse( self.assertFalse(
PortfolioInvitation.objects.filter(email=self.new_member_email, portfolio=self.portfolio).exists(), PortfolioInvitation.objects.filter(email=self.new_member_email, portfolio=self.portfolio).exists(),
"Portfolio invitation should not be created when an EmailSendingError occurs." "Portfolio invitation should not be created when an EmailSendingError occurs.",
) )
@less_console_noise_decorator @less_console_noise_decorator
@ -2727,9 +2724,9 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
def test_submit_new_member_raises_missing_email_error(self, mock_send_email): def test_submit_new_member_raises_missing_email_error(self, mock_send_email):
"""Test when adding a new member and email_send method raises MissingEmailError.""" """Test when adding a new member and email_send method raises MissingEmailError."""
mock_send_email.side_effect = MissingEmailError(self.user.username) mock_send_email.side_effect = MissingEmailError(self.user.username)
self.client.force_login(self.user) self.client.force_login(self.user)
# Simulate a session to ensure continuity # Simulate a session to ensure continuity
session_id = self.client.session.session_key session_id = self.client.session.session_key
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
@ -2739,11 +2736,11 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
"domain_request_permission_member": UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value, "domain_request_permission_member": UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value,
"email": self.new_member_email, "email": self.new_member_email,
} }
# Act # Act
with patch("django.contrib.messages.error") as mock_error: with patch("django.contrib.messages.error") as mock_error:
response = self.client.post(reverse("new-member"), data=form_data) response = self.client.post(reverse("new-member"), data=form_data)
# Assert # Assert
# assert that the send_portfolio_invitation_email called # assert that the send_portfolio_invitation_email called
mock_send_email.assert_called_once_with( mock_send_email.assert_called_once_with(
@ -2753,12 +2750,13 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
self.assertRedirects(response, reverse("members")) self.assertRedirects(response, reverse("members"))
# assert that messages contains message, "Could not send email invitation" # assert that messages contains message, "Could not send email invitation"
mock_error.assert_called_once_with( mock_error.assert_called_once_with(
response.wsgi_request, "Can't send invitation email. No email is associated with the account for 'test_user'." response.wsgi_request,
"Can't send invitation email. No email is associated with the account for 'test_user'.",
) )
# assert that portfolio invitation is not created # assert that portfolio invitation is not created
self.assertFalse( self.assertFalse(
PortfolioInvitation.objects.filter(email=self.new_member_email, portfolio=self.portfolio).exists(), PortfolioInvitation.objects.filter(email=self.new_member_email, portfolio=self.portfolio).exists(),
"Portfolio invitation should not be created when a MissingEmailError occurs." "Portfolio invitation should not be created when a MissingEmailError occurs.",
) )
@less_console_noise_decorator @less_console_noise_decorator
@ -2768,9 +2766,9 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
def test_submit_new_member_raises_exception(self, mock_send_email): def test_submit_new_member_raises_exception(self, mock_send_email):
"""Test when adding a new member and email_send method raises Exception.""" """Test when adding a new member and email_send method raises Exception."""
mock_send_email.side_effect = Exception("Generic exception") mock_send_email.side_effect = Exception("Generic exception")
self.client.force_login(self.user) self.client.force_login(self.user)
# Simulate a session to ensure continuity # Simulate a session to ensure continuity
session_id = self.client.session.session_key session_id = self.client.session.session_key
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
@ -2780,11 +2778,11 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
"domain_request_permission_member": UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value, "domain_request_permission_member": UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value,
"email": self.new_member_email, "email": self.new_member_email,
} }
# Act # Act
with patch("django.contrib.messages.warning") as mock_warning: with patch("django.contrib.messages.warning") as mock_warning:
response = self.client.post(reverse("new-member"), data=form_data) response = self.client.post(reverse("new-member"), data=form_data)
# Assert # Assert
# assert that the send_portfolio_invitation_email called # assert that the send_portfolio_invitation_email called
mock_send_email.assert_called_once_with( mock_send_email.assert_called_once_with(
@ -2793,14 +2791,12 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
# assert that response is a redirect to reverse("members") # assert that response is a redirect to reverse("members")
self.assertRedirects(response, reverse("members")) self.assertRedirects(response, reverse("members"))
# assert that messages contains message, "Could not send email invitation" # assert that messages contains message, "Could not send email invitation"
mock_warning.assert_called_once_with( mock_warning.assert_called_once_with(response.wsgi_request, "Could not send email invitation.")
response.wsgi_request, "Could not send email invitation."
)
# assert that portfolio invitation is not created # assert that portfolio invitation is not created
self.assertFalse( self.assertFalse(
PortfolioInvitation.objects.filter(email=self.new_member_email, portfolio=self.portfolio).exists(), PortfolioInvitation.objects.filter(email=self.new_member_email, portfolio=self.portfolio).exists(),
"Portfolio invitation should not be created when an Exception occurs." "Portfolio invitation should not be created when an Exception occurs.",
) )
@less_console_noise_decorator @less_console_noise_decorator
@override_flag("organization_feature", active=True) @override_flag("organization_feature", active=True)
@ -2828,7 +2824,14 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
# verify messages # verify messages
self.assertContains(response, "This user is already assigned to a portfolio invitation. Based on current waffle flag settings, users cannot be assigned to multiple portfolios.") self.assertContains(
response,
(
"This user is already assigned to a portfolio invitation. "
"Based on current waffle flag settings, users cannot be assigned "
"to multiple portfolios."
),
)
# Validate Database has not changed # Validate Database has not changed
invite_count_after = PortfolioInvitation.objects.count() invite_count_after = PortfolioInvitation.objects.count()
@ -2863,7 +2866,14 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
# Verify messages # Verify messages
self.assertContains(response, "This user is already assigned to a portfolio. Based on current waffle flag settings, users cannot be assigned to multiple portfolios.") self.assertContains(
response,
(
"This user is already assigned to a portfolio. "
"Based on current waffle flag settings, users cannot be "
"assigned to multiple portfolios."
),
)
# Validate Database has not changed # Validate Database has not changed
invite_count_after = PortfolioInvitation.objects.count() invite_count_after = PortfolioInvitation.objects.count()
@ -3013,9 +3023,11 @@ class TestEditPortfolioMemberView(WebTest):
@override_flag("organization_members", active=True) @override_flag("organization_members", active=True)
def test_admin_removing_own_admin_role(self): def test_admin_removing_own_admin_role(self):
"""Tests an admin removing their own admin role redirects to home. """Tests an admin removing their own admin role redirects to home.
Removing the admin role will remove both view and edit members permissions. Removing the admin role will remove both view and edit members permissions.
Note: The user can remove the edit members permissions but as long as they stay in admin role, they will at least still have view members permissions.""" Note: The user can remove the edit members permissions but as long as they
stay in admin role, they will at least still have view members permissions.
"""
self.client.force_login(self.user) self.client.force_login(self.user)

View file

@ -1333,13 +1333,13 @@ class DomainAddUserView(DomainFormBaseView):
elif isinstance(exception, IntegrityError): elif isinstance(exception, IntegrityError):
messages.warning(self.request, f"{email} is already a manager for this domain") messages.warning(self.request, f"{email} is already a manager for this domain")
else: else:
logger.warning("Could not send email invitation (Other Exception)", self.object, exc_info=True) logger.warning("Could not send email invitation (Other Exception)", exc_info=True)
messages.warning(self.request, "Could not send email invitation.") messages.warning(self.request, "Could not send email invitation.")
def _handle_portfolio_exceptions(self, exception, email, portfolio): def _handle_portfolio_exceptions(self, exception, email, portfolio):
"""Handle exceptions raised during the process.""" """Handle exceptions raised during the process."""
if isinstance(exception, EmailSendingError): if isinstance(exception, EmailSendingError):
logger.warning("Could not send email invitation (EmailSendingError)", portfolio, exc_info=True) logger.warning("Could not send email invitation (EmailSendingError)", exc_info=True)
messages.warning(self.request, "Could not send email invitation.") messages.warning(self.request, "Could not send email invitation.")
elif isinstance(exception, MissingEmailError): elif isinstance(exception, MissingEmailError):
messages.error(self.request, str(exception)) messages.error(self.request, str(exception))
@ -1348,7 +1348,7 @@ class DomainAddUserView(DomainFormBaseView):
exc_info=True, exc_info=True,
) )
else: else:
logger.warning("Could not send email invitation (Other Exception)", portfolio, exc_info=True) logger.warning("Could not send email invitation (Other Exception)", exc_info=True)
messages.warning(self.request, "Could not send email invitation.") messages.warning(self.request, "Could not send email invitation.")