I have an ASP.NET MVC app with a basic Register
page. This is the specific function that register's new users.
Register.cshtml.cs:
public async Task<IActionResult> OnPostAsync()
{
var returnUrl = Url.Content("~/Home/PostRegister");
if (ModelState.IsValid)
{
var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = user.Id, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
This is the test that I wrote for it in my integration test:
[Fact]
public async Task DoesRegisterSucceed()
{
// Arrange
var client = _factory.CreateClient(
new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
var postRequest = new HttpRequestMessage(HttpMethod.Post, "/Identity/Account/Register");
var formModel = new Dictionary<string, string>
{
{ "Email", "[email protected]" },
{ "Password", "pas3w0!rRd" },
{ "ConfirmPassword", "pas3w0!rRd" },
};
postRequest.Content = new FormUrlEncodedContent(formModel);
var response = await client.SendAsync(postRequest);
response.EnsureSuccessStatusCode();
//var responseString = await response.Content.ReadAsStringAsync();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
I get this error when I run the test.
Failed amaranth.Tests.AuthTests.Get_ClaimAdminIsReturnedForFirstRegistered [505 ms]
Error Message:
System.Net.Http.HttpRequestException : Response status code does not indicate success: 400 (Bad Request).Stack Trace:
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at amaranth.Tests.AuthTests.Get_ClaimAdminIsReturnedForFirstRegistered() in /path/to/dir/amaranth.Tests/IntegrationTests/AuthTests.cs:line 102
--- End of stack trace from previous location ---
How can I make this test or write a new test that ensures registration succeeds?
Update
In case it's relevant this is my CustomWebApplicationFactory.cs
file that's I'm using:
using System;
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using amaranth.Data;
namespace amaranth.Tests
{
#region snippet1
public class CustomWebApplicationFactory<TStartup>
: WebApplicationFactory<TStartup> where TStartup: class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
var descriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbContextOptions<ApplicationDbContext>));
services.Remove(descriptor);
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
});
var sp = services.BuildServiceProvider();
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<ApplicationDbContext>();
var logger = scopedServices
.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
db.Database.EnsureCreated();
}
});
}
}
#endregion
}
CodePudding user response:
The test is failing because you don't include an antiforgery cookie and verification token in the POST, hence the 400 status code. From this page in the docs:
Any POST request to the SUT must satisfy the antiforgery check that's automatically made by the app's data protection antiforgery system. In order to arrange for a test's POST request, the test app must:
- Make a request for the page.
- Parse the antiforgery cookie and request validation token from the response.
- Make the POST request with the antiforgery cookie and request validation token in place.