diff --git a/test/AuthSamples.FunctionalTests/AuthSamples.FunctionalTests.csproj b/test/AuthSamples.FunctionalTests/AuthSamples.FunctionalTests.csproj
index 0cb04a92fd..4d50d4e6a7 100644
--- a/test/AuthSamples.FunctionalTests/AuthSamples.FunctionalTests.csproj
+++ b/test/AuthSamples.FunctionalTests/AuthSamples.FunctionalTests.csproj
@@ -29,5 +29,6 @@
+
diff --git a/test/AuthSamples.FunctionalTests/CustomPolicyProviderTests.cs b/test/AuthSamples.FunctionalTests/CustomPolicyProviderTests.cs
index 86d6647c45..44eab3973b 100644
--- a/test/AuthSamples.FunctionalTests/CustomPolicyProviderTests.cs
+++ b/test/AuthSamples.FunctionalTests/CustomPolicyProviderTests.cs
@@ -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
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 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()
+ {
+ ["UserName"] = userName,
+ ["DOB"] = dob,
+ });
}
}
}
diff --git a/test/AuthSamples.FunctionalTests/HttpClientExtensions.cs b/test/AuthSamples.FunctionalTests/HttpClientExtensions.cs
new file mode 100644
index 0000000000..b83dfe00de
--- /dev/null
+++ b/test/AuthSamples.FunctionalTests/HttpClientExtensions.cs
@@ -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 SendAsync(
+ this HttpClient client,
+ IHtmlFormElement form,
+ IEnumerable> formValues)
+ {
+ var submitElement = Assert.Single(form.QuerySelectorAll("[type=submit]"));
+ var submitButton = Assert.IsAssignableFrom(submitElement);
+
+ return client.SendAsync(form, submitButton, formValues);
+ }
+
+ // Copied from Identity functionals
+ public static Task SendAsync(
+ this HttpClient client,
+ IHtmlFormElement form,
+ IHtmlElement submitButton,
+ IEnumerable> formValues)
+ {
+ foreach (var kvp in formValues)
+ {
+ var element = Assert.IsAssignableFrom(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);
+ }
+ }
+}
diff --git a/test/AuthSamples.FunctionalTests/TestAssert.cs b/test/AuthSamples.FunctionalTests/TestAssert.cs
new file mode 100644
index 0000000000..6e884e3d69
--- /dev/null
+++ b/test/AuthSamples.FunctionalTests/TestAssert.cs
@@ -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(form);
+ }
+
+ public static IHtmlAnchorElement HasLink(string selector, IHtmlDocument document)
+ {
+ var element = Assert.Single(document.QuerySelectorAll(selector));
+ return Assert.IsAssignableFrom(element);
+ }
+
+ internal static IEnumerable HasElements(string selector, IHtmlDocument document)
+ {
+ var elements = document
+ .QuerySelectorAll(selector)
+ .OfType()
+ .ToArray();
+
+ Assert.NotEmpty(elements);
+
+ return elements;
+ }
+
+ public static IHtmlElement HasElement(string selector, IParentNode document)
+ {
+ var element = Assert.Single(document.QuerySelectorAll(selector));
+ return Assert.IsAssignableFrom(element);
+ }
+
+ public static IHtmlFormElement HasForm(string selector, IParentNode document)
+ {
+ var form = Assert.Single(document.QuerySelectorAll(selector));
+ return Assert.IsAssignableFrom(form);
+ }
+
+ internal static IHtmlHtmlElement IsHtmlFragment(string htmlMessage)
+ {
+ var synteticNode = $"{htmlMessage}
";
+ var fragment = Assert.Single(new HtmlParser().ParseFragment(htmlMessage, context: null));
+ return Assert.IsAssignableFrom(fragment);
+ }
+
+ public static Uri IsRedirect(HttpResponseMessage responseMessage)
+ {
+ Assert.Equal(HttpStatusCode.Redirect, responseMessage.StatusCode);
+ return responseMessage.Headers.Location;
+ }
+
+ public static async Task 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(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);
+ }
+ }
+}