Add some initial functional tests for auth samples (#41)
This commit is contained in:
parent
baa979f5ad
commit
cc47426c77
|
|
@ -3,6 +3,7 @@
|
|||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Package Versions">
|
||||
<AngleSharpPackageVersion>0.9.9</AngleSharpPackageVersion>
|
||||
<InternalAspNetCoreSdkPackageVersion>2.2.0-preview1-17042</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>2.2.0-preview1-34066</MicrosoftAspNetCoreAuthenticationCookiesPackageVersion>
|
||||
<MicrosoftAspNetCoreAuthenticationFacebookPackageVersion>2.2.0-preview1-34066</MicrosoftAspNetCoreAuthenticationFacebookPackageVersion>
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
<form asp-controller="Account" asp-action="Signin" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post">
|
||||
<div>
|
||||
<label>User Name</label>
|
||||
<input type="text" name="userName" />
|
||||
<input id="UserName" type="text" name="userName" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>Date of Birth (MM/DD/YYYY)</label>
|
||||
<input type="text" name="birthDate" />
|
||||
<input id="DOB" type="text" name="birthDate" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -29,5 +29,6 @@
|
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
|
||||
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
|
||||
<PackageReference Include="AngleSharp" Version="$(AngleSharpPackageVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -13,7 +15,7 @@ namespace AuthSamples.FunctionalTests
|
|||
{
|
||||
public CustomPolicyProviderTests(WebApplicationFactory<CustomPolicyProvider.Startup> fixture)
|
||||
{
|
||||
Client = fixture.CreateDefaultClient();
|
||||
Client = fixture.CreateClient();
|
||||
}
|
||||
|
||||
public HttpClient Client { get; }
|
||||
|
|
@ -37,8 +39,70 @@ namespace AuthSamples.FunctionalTests
|
|||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||
Assert.Equal("http://localhost/account/signin?ReturnUrl=%2FHome%2FMinimumAge10", response.Headers.Location.ToString());
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("http://localhost/account/signin?ReturnUrl=%2FHome%2FMinimumAge10", response.RequestMessage.RequestUri.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MinimumAge10WorksIfOldEnough()
|
||||
{
|
||||
// Arrange & Act
|
||||
var signIn = await SignIn(Client, "Dude", DateTime.Now.Subtract(TimeSpan.FromDays(365 * 20)).ToShortDateString());
|
||||
Assert.Equal(HttpStatusCode.OK, signIn.StatusCode);
|
||||
|
||||
var response = await Client.GetAsync("/Home/MinimumAge10");
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Contains("Welcome, Dude", content);
|
||||
Assert.Contains("Welcome to a page restricted to users 10 or older", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MinimumAge10FailsIfNotOldEnough()
|
||||
{
|
||||
// Arrange & Act
|
||||
var signIn = await SignIn(Client, "Dude", DateTime.Now.Subtract(TimeSpan.FromDays(365 * 5)).ToShortDateString());
|
||||
Assert.Equal(HttpStatusCode.OK, signIn.StatusCode);
|
||||
|
||||
var response = await Client.GetAsync("/Home/MinimumAge10");
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Contains("Access Denied: Dude is not authorized to view this page.", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MinimumAge50WorksIfOldEnough()
|
||||
{
|
||||
// Arrange & Act
|
||||
var signIn = await SignIn(Client, "Dude", DateTime.Now.Subtract(TimeSpan.FromDays(365 * 55)).ToShortDateString());
|
||||
Assert.Equal(HttpStatusCode.OK, signIn.StatusCode);
|
||||
|
||||
var response = await Client.GetAsync("/Home/MinimumAge50");
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Contains("Welcome, Dude", content);
|
||||
Assert.Contains("Welcome to a page restricted to users 50 or older", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MinimumAge50FailsIfNotOldEnough()
|
||||
{
|
||||
// Arrange & Act
|
||||
var signIn = await SignIn(Client, "Dude", DateTime.Now.Subtract(TimeSpan.FromDays(365 * 20)).ToShortDateString());
|
||||
Assert.Equal(HttpStatusCode.OK, signIn.StatusCode);
|
||||
|
||||
var response = await Client.GetAsync("/Home/MinimumAge50");
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Contains("Access Denied: Dude is not authorized to view this page.", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -49,8 +113,21 @@ namespace AuthSamples.FunctionalTests
|
|||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||
Assert.Equal("http://localhost/account/signin?ReturnUrl=%2FHome%2FMinimumAge50", response.Headers.Location.ToString());
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("http://localhost/account/signin?ReturnUrl=%2FHome%2FMinimumAge50", response.RequestMessage.RequestUri.ToString());
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> SignIn(HttpClient client, string userName, string dob)
|
||||
{
|
||||
var goToSignIn = await client.GetAsync("/account/signin");
|
||||
var signIn = await TestAssert.IsHtmlDocumentAsync(goToSignIn);
|
||||
|
||||
var form = TestAssert.HasForm(signIn);
|
||||
return await client.SendAsync(form, new Dictionary<string, string>()
|
||||
{
|
||||
["UserName"] = userName,
|
||||
["DOB"] = dob,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Dom.Html;
|
||||
using Xunit;
|
||||
|
||||
namespace AuthSamples.FunctionalTests
|
||||
{
|
||||
public static class HttpClientExtensions
|
||||
{
|
||||
// Copied from Identity functionals
|
||||
public static Task<HttpResponseMessage> SendAsync(
|
||||
this HttpClient client,
|
||||
IHtmlFormElement form,
|
||||
IEnumerable<KeyValuePair<string, string>> formValues)
|
||||
{
|
||||
var submitElement = Assert.Single(form.QuerySelectorAll("[type=submit]"));
|
||||
var submitButton = Assert.IsAssignableFrom<IHtmlElement>(submitElement);
|
||||
|
||||
return client.SendAsync(form, submitButton, formValues);
|
||||
}
|
||||
|
||||
// Copied from Identity functionals
|
||||
public static Task<HttpResponseMessage> SendAsync(
|
||||
this HttpClient client,
|
||||
IHtmlFormElement form,
|
||||
IHtmlElement submitButton,
|
||||
IEnumerable<KeyValuePair<string, string>> formValues)
|
||||
{
|
||||
foreach (var kvp in formValues)
|
||||
{
|
||||
var element = Assert.IsAssignableFrom<IHtmlInputElement>(form[kvp.Key]);
|
||||
element.Value = kvp.Value;
|
||||
}
|
||||
|
||||
var submit = form.GetSubmission(submitButton);
|
||||
var target = (Uri)submit.Target;
|
||||
if (submitButton.HasAttribute("formaction"))
|
||||
{
|
||||
var formaction = submitButton.GetAttribute("formaction");
|
||||
target = new Uri(formaction, UriKind.Relative);
|
||||
}
|
||||
var submision = new HttpRequestMessage(new HttpMethod(submit.Method.ToString()), target)
|
||||
{
|
||||
Content = new StreamContent(submit.Body)
|
||||
};
|
||||
|
||||
foreach (var header in submit.Headers)
|
||||
{
|
||||
if (!submision.Headers.TryAddWithoutValidation(header.Key, header.Value))
|
||||
{
|
||||
submision.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return client.SendAsync(submision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp;
|
||||
using AngleSharp.Dom;
|
||||
using AngleSharp.Dom.Html;
|
||||
using AngleSharp.Network;
|
||||
using AngleSharp.Parser.Html;
|
||||
using Xunit;
|
||||
|
||||
namespace AuthSamples.FunctionalTests
|
||||
{
|
||||
// Merged HtmlAssert + ResponseAssert from Identity functional tests
|
||||
public class TestAssert
|
||||
{
|
||||
public static IHtmlFormElement HasForm(IHtmlDocument document)
|
||||
{
|
||||
var form = Assert.Single(document.QuerySelectorAll("form"));
|
||||
return Assert.IsAssignableFrom<IHtmlFormElement>(form);
|
||||
}
|
||||
|
||||
public static IHtmlAnchorElement HasLink(string selector, IHtmlDocument document)
|
||||
{
|
||||
var element = Assert.Single(document.QuerySelectorAll(selector));
|
||||
return Assert.IsAssignableFrom<IHtmlAnchorElement>(element);
|
||||
}
|
||||
|
||||
internal static IEnumerable<IHtmlElement> HasElements(string selector, IHtmlDocument document)
|
||||
{
|
||||
var elements = document
|
||||
.QuerySelectorAll(selector)
|
||||
.OfType<IHtmlElement>()
|
||||
.ToArray();
|
||||
|
||||
Assert.NotEmpty(elements);
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
public static IHtmlElement HasElement(string selector, IParentNode document)
|
||||
{
|
||||
var element = Assert.Single(document.QuerySelectorAll(selector));
|
||||
return Assert.IsAssignableFrom<IHtmlElement>(element);
|
||||
}
|
||||
|
||||
public static IHtmlFormElement HasForm(string selector, IParentNode document)
|
||||
{
|
||||
var form = Assert.Single(document.QuerySelectorAll(selector));
|
||||
return Assert.IsAssignableFrom<IHtmlFormElement>(form);
|
||||
}
|
||||
|
||||
internal static IHtmlHtmlElement IsHtmlFragment(string htmlMessage)
|
||||
{
|
||||
var synteticNode = $"<div>{htmlMessage}</div>";
|
||||
var fragment = Assert.Single(new HtmlParser().ParseFragment(htmlMessage, context: null));
|
||||
return Assert.IsAssignableFrom<IHtmlHtmlElement>(fragment);
|
||||
}
|
||||
|
||||
public static Uri IsRedirect(HttpResponseMessage responseMessage)
|
||||
{
|
||||
Assert.Equal(HttpStatusCode.Redirect, responseMessage.StatusCode);
|
||||
return responseMessage.Headers.Location;
|
||||
}
|
||||
|
||||
public static async Task<IHtmlDocument> IsHtmlDocumentAsync(HttpResponseMessage response)
|
||||
{
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/html", response.Content.Headers.ContentType.MediaType);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
var document = await BrowsingContext.New()
|
||||
.OpenAsync(ResponseFactory, CancellationToken.None);
|
||||
return Assert.IsAssignableFrom<IHtmlDocument>(document);
|
||||
|
||||
void ResponseFactory(VirtualResponse htmlResponse)
|
||||
{
|
||||
htmlResponse
|
||||
.Address(response.RequestMessage.RequestUri)
|
||||
.Status(response.StatusCode);
|
||||
|
||||
MapHeaders(response.Headers);
|
||||
MapHeaders(response.Content.Headers);
|
||||
|
||||
htmlResponse.Content(content);
|
||||
|
||||
void MapHeaders(HttpHeaders headers)
|
||||
{
|
||||
foreach (var header in headers)
|
||||
{
|
||||
foreach (var value in header.Value)
|
||||
{
|
||||
htmlResponse.Header(header.Key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void IsOK(HttpResponseMessage download)
|
||||
{
|
||||
Assert.Equal(HttpStatusCode.OK, download.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue