diff --git a/Directory.Packages.props b/Directory.Packages.props
index 80fd26b8..36a36101 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -49,6 +49,7 @@
+
diff --git a/src/Web/Controllers/ManageController.cs b/src/Web/Controllers/ManageController.cs
index e4748b64..4471e91c 100644
--- a/src/Web/Controllers/ManageController.cs
+++ b/src/Web/Controllers/ManageController.cs
@@ -107,16 +107,7 @@ public async Task SendVerificationEmail(IndexViewModel model)
var user = await GetCurrentUserAsync();
- var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
- var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
- Guard.Against.Null(callbackUrl, nameof(callbackUrl));
- var email = user.Email;
- if (email == null)
- {
- throw new ApplicationException($"No email associated with user {user.UserName}'.");
- }
-
- await _emailSender.SendEmailConfirmationAsync(email, callbackUrl);
+ await SendVerificationEmailInternalAsync(user);
StatusMessage = "Verification email sent. Please check your email.";
return RedirectToAction(nameof(MyAccount));
@@ -491,4 +482,19 @@ private async Task GetCurrentUserAsync()
return user ?? throw new UserNotFoundException(_userManager.GetUserId(User) ?? string.Empty);
}
+ protected virtual async Task SendVerificationEmailInternalAsync(ApplicationUser user)
+ {
+ var email = user.Email;
+ if(email == null)
+ {
+ throw new ApplicationException($"No email associated with user {user.UserName}'.");
+ }
+
+ var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
+ var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
+ Guard.Against.Null(callbackUrl, nameof(callbackUrl));
+
+ await _emailSender.SendEmailConfirmationAsync(email, callbackUrl);
+ }
+
}
diff --git a/tests/UnitTests/UnitTests.csproj b/tests/UnitTests/UnitTests.csproj
index d969b6f4..a60f15f8 100644
--- a/tests/UnitTests/UnitTests.csproj
+++ b/tests/UnitTests/UnitTests.csproj
@@ -14,6 +14,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
+
all
diff --git a/tests/UnitTests/Web/Controllers/ManageControllerTests.cs b/tests/UnitTests/Web/Controllers/ManageControllerTests.cs
new file mode 100644
index 00000000..e1a23310
--- /dev/null
+++ b/tests/UnitTests/Web/Controllers/ManageControllerTests.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Security.Claims;
+using System.Text;
+using System.Text.Encodings.Web;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.eShopWeb.ApplicationCore.Interfaces;
+using Microsoft.eShopWeb.Infrastructure.Identity;
+using Microsoft.eShopWeb.Web.Controllers;
+using Microsoft.eShopWeb.Web.Services;
+using Moq;
+using Xunit;
+using Microsoft.AspNetCore.Mvc.Routing;
+
+namespace Microsoft.eShopWeb.UnitTests.Web.Controllers;
+public class ManageControllerTests
+{
+ [Fact]
+ public async Task SendVerificationEmail_sends_email()
+ {
+ // Arrange
+ var user = new ApplicationUser
+ {
+ Id = "user-id",
+ Email = "test@test.com",
+ UserName = "test"
+ };
+
+ var userManager = TestUserManager(user);
+ var signInManager = TestSignInManager(userManager);
+
+ var emailSender = new Mock();
+ emailSender.Setup(e => e.SendEmailAsync(
+ user.Email,
+ It.IsAny(),
+ It.IsAny()))
+ .Returns(Task.CompletedTask);
+
+ var logger = new Mock>();
+ var urlEncoder = UrlEncoder.Default;
+
+ var controller = new TestableManageController(
+ userManager,
+ signInManager,
+ emailSender.Object,
+ logger.Object,
+ urlEncoder);
+
+ controller.ControllerContext = new ControllerContext
+ {
+ HttpContext = new DefaultHttpContext
+ {
+ User = new ClaimsPrincipal(new ClaimsIdentity(
+ new[] { new Claim(ClaimTypes.NameIdentifier, user.Id) }))
+ }
+ };
+
+ var urlHelper = new Mock();
+ urlHelper.Setup(u => u.Action(It.IsAny()))
+ .Returns("https://localhost/confirm-email");
+
+ controller.Url = urlHelper.Object;
+
+ // Act
+ await controller.InvokeSendVerificationEmail(user);
+
+ // Assert
+ emailSender.Verify(e => e.SendEmailAsync(
+ user.Email,
+ It.IsAny(),
+ It.IsAny()),
+ Times.Once);
+ }
+
+ #region Helpers
+ private static UserManager TestUserManager(ApplicationUser user)
+ {
+ var store = new Mock>();
+
+ var manager = new Mock>(
+ store.Object,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ manager.Setup(m => m.GetUserAsync(It.IsAny()))
+ .ReturnsAsync(user);
+
+ manager.Setup(m => m.GenerateEmailConfirmationTokenAsync(user))
+ .ReturnsAsync("token");
+
+ return manager.Object;
+ }
+
+ private static SignInManager TestSignInManager(
+ UserManager userManager)
+ {
+ return new SignInManager(
+ userManager,
+ new Mock().Object,
+ new Mock>().Object,
+ null,
+ null,
+ null,
+ null);
+ }
+ #endregion
+
+
+ internal class TestableManageController : ManageController
+ {
+ public TestableManageController(
+ UserManager userManager,
+ SignInManager signInManager,
+ IEmailSender emailSender,
+ IAppLogger logger,
+ UrlEncoder urlEncoder)
+ : base(userManager, signInManager, emailSender, logger, urlEncoder)
+ {
+ }
+
+ public Task InvokeSendVerificationEmail(ApplicationUser user) => SendVerificationEmailInternalAsync(user);
+ }
+}