From 70cd6167152a423a8d7bc96950ebad4232be6f9b Mon Sep 17 00:00:00 2001 From: RaceProUK Date: Thu, 24 Aug 2023 11:16:39 +0100 Subject: [PATCH] Add simplified assertions for PageResult and RedirectToPageResult --- .../ActionResultAssertions.cs | 43 ++++++ .../PageResultAssertions.cs | 25 +++ .../RedirectToPageResultAssertions.cs | 139 +++++++++++++++++ .../ActionResultAssertions_Tests.cs | 21 +++ .../RedirectToPageResultAssertions_Tests.cs | 142 ++++++++++++++++++ 5 files changed, 370 insertions(+) create mode 100644 src/FluentAssertions.AspNetCore.Mvc/PageResultAssertions.cs create mode 100644 src/FluentAssertions.AspNetCore.Mvc/RedirectToPageResultAssertions.cs create mode 100644 tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectToPageResultAssertions_Tests.cs diff --git a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs index 55bc290..8cdc9be 100644 --- a/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs +++ b/src/FluentAssertions.AspNetCore.Mvc/ActionResultAssertions.cs @@ -1,6 +1,7 @@ using FluentAssertions.Execution; using FluentAssertions.Primitives; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; using System.Diagnostics; namespace FluentAssertions.AspNetCore.Mvc @@ -284,6 +285,27 @@ public ViewResultAssertions BeViewResult(string reason = "", params object[] rea return new ViewResultAssertions(Subject as ViewResult); } + /// + /// Asserts that the subject is a . + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + [CustomAssertion] + public PageResultAssertions BePageResult(string reason = "", params object[] reasonArgs) + { + Execute.Assertion + .BecauseOf(reason, reasonArgs) + .ForCondition(Subject is PageResult) + .FailWith(FailureMessages.CommonTypeFailMessage, typeof(PageResult), Subject.GetType()); + + return new PageResultAssertions(Subject as PageResult); + } + /// /// Asserts that the subject is a . /// @@ -305,6 +327,27 @@ public RedirectToActionResultAssertions BeRedirectToActionResult(string reason = return new RedirectToActionResultAssertions(Subject as RedirectToActionResult); } + /// + /// Asserts that the subject is a . + /// + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + [CustomAssertion] + public RedirectToPageResultAssertions BeRedirectToPageResult(string reason = "", params object[] reasonArgs) + { + Execute.Assertion + .BecauseOf(reason, reasonArgs) + .ForCondition(Subject is RedirectToPageResult) + .FailWith(FailureMessages.CommonTypeFailMessage, typeof(RedirectToPageResult), Subject.GetType()); + + return new RedirectToPageResultAssertions(Subject as RedirectToPageResult); + } + /// /// Asserts that the subject is a . /// diff --git a/src/FluentAssertions.AspNetCore.Mvc/PageResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/PageResultAssertions.cs new file mode 100644 index 0000000..cc0e31b --- /dev/null +++ b/src/FluentAssertions.AspNetCore.Mvc/PageResultAssertions.cs @@ -0,0 +1,25 @@ +using FluentAssertions.Primitives; +using Microsoft.AspNetCore.Mvc.RazorPages; +using System.Diagnostics; + +namespace FluentAssertions.AspNetCore.Mvc +{ + /// + /// Contains a number of methods to assert that a is in the expected state. + /// + [DebuggerNonUserCode] + public class PageResultAssertions : ObjectAssertions + { + #region Public Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The object to test assertion on + public PageResultAssertions(PageResult subject) : base(subject) + { + } + + #endregion Public Constructors + } +} \ No newline at end of file diff --git a/src/FluentAssertions.AspNetCore.Mvc/RedirectToPageResultAssertions.cs b/src/FluentAssertions.AspNetCore.Mvc/RedirectToPageResultAssertions.cs new file mode 100644 index 0000000..6cae7f5 --- /dev/null +++ b/src/FluentAssertions.AspNetCore.Mvc/RedirectToPageResultAssertions.cs @@ -0,0 +1,139 @@ +using FluentAssertions.Execution; +using FluentAssertions.Primitives; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Diagnostics; + +namespace FluentAssertions.AspNetCore.Mvc +{ + /// + /// Contains a number of methods to assert that a is in the expected state. + /// + [DebuggerNonUserCode] + public class RedirectToPageResultAssertions : ObjectAssertions + { + /// + /// Initializes a new instance of the class. + /// + public RedirectToPageResultAssertions(RedirectToPageResult subject) : base(subject) { } + + private RedirectToPageResult RedirectToPageResultSubject => Subject as RedirectToPageResult; + + /// + /// Asserts that the page name is the expected page. + /// + /// The expected page. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public RedirectToPageResultAssertions WithPageName(string expectedPageName, string reason = "", params object[] reasonArgs) + { + string actualPageName = RedirectToPageResultSubject.PageName; + + Execute.Assertion + .ForCondition(string.Equals(actualPageName, expectedPageName, StringComparison.OrdinalIgnoreCase)) + .BecauseOf(reason, reasonArgs) + .WithDefaultIdentifier("RedirectToPageResult.PageName") + .FailWith(FailureMessages.CommonFailMessage, expectedPageName, actualPageName); + + return this; + } + + /// + /// Asserts that the fragment is the expected fragment. + /// + /// The expected fragment. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public RedirectToPageResultAssertions WithFragment(string expectedFragment, string reason = "", params object[] reasonArgs) + { + string actualFragment = RedirectToPageResultSubject.Fragment; + + Execute.Assertion + .ForCondition(string.Equals(actualFragment, expectedFragment, StringComparison.OrdinalIgnoreCase)) + .BecauseOf(reason, reasonArgs) + .WithDefaultIdentifier("RedirectToPageResult.Fragment") + .FailWith(FailureMessages.CommonFailMessage, expectedFragment, actualFragment); + + return this; + } + + /// + /// Asserts that the redirect to page is permanent. + /// + /// Should the expected redirect be permanent. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public RedirectToPageResultAssertions WithPermanent(bool expectedPermanent, string reason = "", params object[] reasonArgs) + { + bool actualPermanent = RedirectToPageResultSubject.Permanent; + + Execute.Assertion + .ForCondition(expectedPermanent == actualPermanent) + .BecauseOf(reason, reasonArgs) + .WithDefaultIdentifier("RedirectToPageResult.Permanent") + .FailWith(FailureMessages.CommonFailMessage, expectedPermanent, actualPermanent); + + return this; + } + + /// + /// Asserts that the redirect preserves the original request method. + /// + /// Should the expected redirect preserve the original request method. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public RedirectToPageResultAssertions WithPreserveMethod(bool expectedPreserveMethod, string reason = "", params object[] reasonArgs) + { + bool actualPreserveMethod = RedirectToPageResultSubject.PreserveMethod; + + Execute.Assertion + .ForCondition(expectedPreserveMethod == actualPreserveMethod) + .BecauseOf(reason, reasonArgs) + .WithDefaultIdentifier("RedirectToPageResult.PreserveMethod") + .FailWith(FailureMessages.CommonFailMessage, expectedPreserveMethod, actualPreserveMethod); + + return this; + } + + /// + /// Asserts that the redirect has the expected route value. + /// + /// The expected key. + /// The expected value. + /// + /// A formatted phrase as is supported by explaining why the assertion + /// is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public RedirectToPageResultAssertions WithRouteValue(string key, object expectedValue, string reason = "", params object[] reasonArgs) + { + var subjectTyped = RedirectToPageResultSubject; + + AssertionHelpers.AssertStringObjectDictionary(subjectTyped.RouteValues, "RedirectToPageResult.RouteValues", key, expectedValue, reason, reasonArgs); + + return this; + } + } +} diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs index e2f3b00..c3c14cc 100644 --- a/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/ActionResultAssertions_Tests.cs @@ -1,6 +1,7 @@ using FluentAssertions.AspNetCore.Mvc.Tests.Helpers; using FluentAssertions.Mvc.Tests.Helpers; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Routing; using System; using Xunit; @@ -262,6 +263,26 @@ public void BeView_GivenNotView_ShouldFail() .WithMessage(failureMessage); } + [Fact] + public void BePage_GivenPage_ShouldPass() + { + ActionResult result = new PageResult(); + + result.Should().BePageResult(); + } + + [Fact] + public void BePage_GivenNotPage_ShouldFail() + { + ActionResult result = new RedirectResult("/"); + var failureMessage = FailureMessageHelper.ExpectedContextTypeXButFoundYWithReason("result", typeof(PageResult), typeof(RedirectResult)); + + Action a = () => result.Should().BePageResult(Reason, ReasonArgs); + + a.Should().Throw() + .WithMessage(failureMessage); + } + [Fact] public void BeStatusCodeResult_GivenStatusCodeResult_ShouldPass() { diff --git a/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectToPageResultAssertions_Tests.cs b/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectToPageResultAssertions_Tests.cs new file mode 100644 index 0000000..69e364b --- /dev/null +++ b/tests/FluentAssertions.AspNetCore.Mvc.Tests/RedirectToPageResultAssertions_Tests.cs @@ -0,0 +1,142 @@ +using FluentAssertions.Mvc.Tests.Helpers; +using Microsoft.AspNetCore.Mvc; +using System; +using Xunit; + +namespace FluentAssertions.AspNetCore.Mvc.Tests +{ + + public class RedirectToPageResultAssertions_Tests + { + public const string Reason = FailureMessageHelper.Reason; + public readonly static object[] ReasonArgs = FailureMessageHelper.ReasonArgs; + + [Fact] + public void WithPageName_GivenExpectedPageName_ShouldPass() + { + var expectedPageName = "expectedPage"; + RedirectToPageResult result = new RedirectToPageResult(expectedPageName, string.Empty, null); + + result.Should().BeRedirectToPageResult() + .WithPageName(expectedPageName); + } + + [Fact] + public void WithPageName_GivenUnexpectedPageName_ShouldFail() + { + RedirectToPageResult result = new RedirectToPageResult("someOtherPage", string.Empty, null); + + Action a = () => result.Should().BeRedirectToPageResult() + .WithPageName("expectedPage", Reason, ReasonArgs); + + a.Should().Throw() + .WithMessage(FailureMessageHelper.ExpectedContextToBeXButY("RedirectToPageResult.PageName", "expectedPage", "someOtherPage")); + } + + [Fact] + public void WithFragment_GivenExpectedFragment_ShouldPass() + { + var expectedFragment = "expectedFragment"; + RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, false, expectedFragment); + + result.Should().BeRedirectToPageResult() + .WithFragment(expectedFragment); + } + + [Fact] + public void WithFragment_GivenUnexpectedFragment_ShouldFail() + { + RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, false, "someOtherFragment"); + + Action a = () => result.Should().BeRedirectToPageResult() + .WithFragment("expectedFragment", Reason, ReasonArgs); + + a.Should().Throw() + .WithMessage(FailureMessageHelper.ExpectedContextToBeXButY("RedirectToPageResult.Fragment", "expectedFragment", "someOtherFragment")); + } + + [Fact] + public void WithPermanent_GivenExpectedValue_ShouldPass() + { + RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, true); + + result.Should().BeRedirectToPageResult() + .WithPermanent(true); + } + + [Fact] + public void WithPermanent_GivenUnexpectedValue_ShouldFail() + { + RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, true); + + Action a = () => result.Should().BeRedirectToPageResult() + .WithPermanent(false, Reason, ReasonArgs); + + a.Should().Throw() + .WithMessage(FailureMessageHelper.ExpectedContextToBeXButY("RedirectToPageResult.Permanent", false, true)); + } + + [Fact] + public void WithPreservedMethod_GivenExpectedValue_ShouldPass() + { + RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, false, true); + + result.Should().BeRedirectToPageResult() + .WithPreserveMethod(true); + } + + [Fact] + public void WithPreserveMethod_GivenUnexpectedValue_ShouldFail() + { + RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, null, false, true); + + Action a = () => result.Should().BeRedirectToPageResult() + .WithPreserveMethod(false, Reason, ReasonArgs); + + a.Should().Throw() + .WithMessage(FailureMessageHelper.ExpectedContextToBeXButY("RedirectToPageResult.PreserveMethod", false, true)); + } + + [Fact] + public void WithRouteValue_GivenKeyDoesntExist_ShouldFail() + { + var expectedKey = "expectedKey"; + var failureMessage = FailureMessageHelper.ExpectedKeyButNotFound("RedirectToPageResult.RouteValues", expectedKey, "Val"); + + var routeValues = new { myKey = "MyValue" }; + RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, routeValues); + + Action a = () => result.Should().BeRedirectToPageResult().WithRouteValue(expectedKey, "Val", Reason, ReasonArgs); + + a.Should().Throw() + .WithMessage(failureMessage); + } + + [Fact] + public void WithRouteValue_GivenExpectedKeyValuePair_ShouldPass() + { + var expectedKey = "expectedKey"; + var expectedValue = "expectedValue"; + var routeValues = new { expectedKey = expectedValue }; + + RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, routeValues); + + result.Should().BeRedirectToPageResult().WithRouteValue(expectedKey, expectedValue); + } + + [Fact] + public void HaveValue_GivenUnexpectedKeyValuePair_ShouldFail() + { + var expectedKey = "expectedKey"; + var expectedValue = "expectedValue"; + var routeValues = new { expectedKey = "someOtherValue" }; + var failureMessage = FailureMessageHelper.ExpectedAtKeyValueXButFoundY("RedirectToPageResult.RouteValues", expectedKey, expectedValue, "someOtherValue"); + + RedirectToPageResult result = new RedirectToPageResult(string.Empty, string.Empty, routeValues); + Action a = () => result.Should().BeRedirectToPageResult().WithRouteValue(expectedKey, expectedValue, Reason, ReasonArgs); + + a.Should().Throw() + .WithMessage(failureMessage); + } + } +}