Add some initial functional tests for auth samples (#41)

This commit is contained in:
Hao Kung 2018-05-01 13:04:56 -07:00 committed by GitHub
parent baa979f5ad
commit cc47426c77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 260 additions and 7 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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,
});
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}