diff --git a/Taarafo.Portal.Web.Tests.Unit/Components/PostComponents/PostRemoveComponentTests.Exceptions.cs b/Taarafo.Portal.Web.Tests.Unit/Components/PostComponents/PostRemoveComponentTests.Exceptions.cs new file mode 100644 index 0000000..8588491 --- /dev/null +++ b/Taarafo.Portal.Web.Tests.Unit/Components/PostComponents/PostRemoveComponentTests.Exceptions.cs @@ -0,0 +1,70 @@ +// --------------------------------------------------------------- +// Copyright (c) Coalition of the Good-Hearted Engineers +// FREE TO USE TO CONNECT THE WORLD +// --------------------------------------------------------------- + +using System; +using Bunit; +using FluentAssertions; +using Moq; +using Taarafo.Portal.Web.Models.PostViews; +using Taarafo.Portal.Web.Models.Views.Components.PostComponents; +using Taarafo.Portal.Web.Views.Components.PostComponents; +using Xunit; + +namespace Taarafo.Portal.Web.Tests.Unit.Components.PostComponents +{ + public partial class PostRemoveComponentTests + { + [Fact] + public void ShouldRenderErrorIfExceptionOccurs() + { + // given + PostRemoveComponentState expectedState = + PostRemoveComponentState.Error; + + PostView somePostView = CreateRandomPostView(); + + string randomMessage = GetRandomString(); + string exceptionMessage = randomMessage; + string expectedErrorMessage = exceptionMessage; + string expectedImageUrl = "imgs/error.png"; + + var exception = + new Exception(message: exceptionMessage); + + this.postViewServiceMock.Setup(service => + service.RemovePostViewByIdAsync(somePostView.Id)) + .ThrowsAsync(exception); + + ComponentParameter inputComponentParameter = + ComponentParameter.CreateParameter( + name: nameof(PostView), + value: somePostView); + + // when + this.postRemoveRenderedComponent = + RenderComponent(inputComponentParameter); + + this.postRemoveRenderedComponent.Instance.Button.Click(); + + this.postRemoveRenderedComponent.Render(); + + // then + this.postRemoveRenderedComponent.Instance.State + .Should().Be(expectedState); + + this.postRemoveRenderedComponent.Instance.ErrorMessage + .Should().Be(expectedErrorMessage); + + this.postRemoveRenderedComponent.Instance.ErrorImage.Url + .Should().Be(expectedImageUrl); + + this.postViewServiceMock.Verify(service => + service.RemovePostViewByIdAsync(somePostView.Id), + Times.Once); + + this.postViewServiceMock.VerifyNoOtherCalls(); + } + } +} diff --git a/Taarafo.Portal.Web.Tests.Unit/Components/PostComponents/PostRemoveComponentTests.Render.cs b/Taarafo.Portal.Web.Tests.Unit/Components/PostComponents/PostRemoveComponentTests.Render.cs new file mode 100644 index 0000000..006b472 --- /dev/null +++ b/Taarafo.Portal.Web.Tests.Unit/Components/PostComponents/PostRemoveComponentTests.Render.cs @@ -0,0 +1,101 @@ +// --------------------------------------------------------------- +// Copyright (c) Coalition of the Good-Hearted Engineers +// FREE TO USE TO CONNECT THE WORLD +// --------------------------------------------------------------- + +using Bunit; +using FluentAssertions; +using Moq; +using Taarafo.Portal.Web.Models.PostViews; +using Taarafo.Portal.Web.Models.Views.Components.PostComponents; +using Taarafo.Portal.Web.Views.Components.PostComponents; +using Xunit; + +namespace Taarafo.Portal.Web.Tests.Unit.Components.PostComponents +{ + public partial class PostRemoveComponentTests + { + [Fact] + public void ShouldInitializeComponent() + { + // given + PostRemoveComponentState expectedState = + PostRemoveComponentState.Loading; + + // when + var initialPostRemove = new PostRemoveComponent(); + + // then + initialPostRemove.State.Should().Be(expectedState); + initialPostRemove.PostViewService.Should().BeNull(); + initialPostRemove.PostView.Should().BeNull(); + initialPostRemove.Button.Should().BeNull(); + } + + [Fact] + public void ShouldRenderComponent() + { + // given + PostRemoveComponentState expectedState = + PostRemoveComponentState.Content; + + string expectedLabel = "🗑"; + + PostView randomPostView = CreateRandomPostView(); + PostView inputPostView = randomPostView; + PostView expectedPostView = inputPostView; + + ComponentParameter inputComponentParameter = + ComponentParameter.CreateParameter( + name: nameof(PostView), + value: inputPostView); + + // when + this.postRemoveRenderedComponent = + RenderComponent(inputComponentParameter); + + // then + this.postRemoveRenderedComponent.Instance.State.Should().Be(expectedState); + this.postRemoveRenderedComponent.Instance.PostViewService.Should().NotBeNull(); + this.postRemoveRenderedComponent.Instance.PostView.Should().BeEquivalentTo(expectedPostView); + this.postRemoveRenderedComponent.Instance.Button.Label.Should().Be(expectedLabel); + this.postRemoveRenderedComponent.Instance.Button.IsDisabled.Should().BeFalse(); + this.postRemoveRenderedComponent.Instance.Button.OnClick.Should().NotBeNull(); + } + + [Fact] + public void ShouldRemovePostAsync() + { + // given + PostView randomPostView = CreateRandomPostView(); + PostView inputPostView = randomPostView; + PostView expectedPostView = inputPostView; + + ComponentParameter inputComponentParameter = + ComponentParameter.CreateParameter( + name: nameof(PostView), + value: inputPostView); + + // when + this.postRemoveRenderedComponent = + RenderComponent(inputComponentParameter); + + this.postRemoveRenderedComponent.Instance.Button + .Click(); + + // then + this.postRemoveRenderedComponent.Instance.Button.IsDisabled + .Should().BeTrue(); + + this.postRemoveRenderedComponent.Instance.PostView + .Should().BeEquivalentTo(expectedPostView); + + this.postViewServiceMock.Verify(service => + service.RemovePostViewByIdAsync( + this.postRemoveRenderedComponent.Instance.PostView.Id), + Times.Once); + + this.postViewServiceMock.VerifyNoOtherCalls(); + } + } +} diff --git a/Taarafo.Portal.Web.Tests.Unit/Components/PostComponents/PostRemoveComponentTests.cs b/Taarafo.Portal.Web.Tests.Unit/Components/PostComponents/PostRemoveComponentTests.cs new file mode 100644 index 0000000..4dc61b1 --- /dev/null +++ b/Taarafo.Portal.Web.Tests.Unit/Components/PostComponents/PostRemoveComponentTests.cs @@ -0,0 +1,54 @@ +// --------------------------------------------------------------- +// Copyright (c) Coalition of the Good-Hearted Engineers +// FREE TO USE TO CONNECT THE WORLD +// --------------------------------------------------------------- + +using System; +using Bunit; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Syncfusion.Blazor; +using Taarafo.Portal.Web.Models.PostViews; +using Taarafo.Portal.Web.Services.Views.PostViews; +using Taarafo.Portal.Web.Views.Components.PostComponents; +using Tynamix.ObjectFiller; + +namespace Taarafo.Portal.Web.Tests.Unit.Components.PostComponents +{ + public partial class PostRemoveComponentTests : TestContext + { + private readonly Mock postViewServiceMock; + private IRenderedComponent postRemoveRenderedComponent; + + public PostRemoveComponentTests() + { + this.postViewServiceMock = new Mock(); + this.Services.AddTransient(service => this.postViewServiceMock.Object); + this.Services.AddSyncfusionBlazor(); + this.Services.AddOptions(); + this.JSInterop.Mode = JSRuntimeMode.Loose; + } + + private static PostView CreateRandomPostView() => + CreatePostViewFiller().Create(); + + private static DateTimeOffset GetRandomDateTimeOffset() => + new DateTimeRange(earliestDate: new DateTime()).GetValue(); + + private static string GetRandomString() => + new MnemonicString(wordCount: GetRandomNumber()).GetValue(); + + private static int GetRandomNumber() => + new IntRange(min: 2, max: 10).GetValue(); + + private static Filler CreatePostViewFiller() + { + var filler = new Filler(); + + filler.Setup() + .OnType().Use(GetRandomDateTimeOffset()); + + return filler; + } + } +} diff --git a/Taarafo.Portal.Web/Models/Views/Components/PostComponents/PostRemoveComponentState.cs b/Taarafo.Portal.Web/Models/Views/Components/PostComponents/PostRemoveComponentState.cs new file mode 100644 index 0000000..3874b0c --- /dev/null +++ b/Taarafo.Portal.Web/Models/Views/Components/PostComponents/PostRemoveComponentState.cs @@ -0,0 +1,14 @@ +// --------------------------------------------------------------- +// Copyright (c) Coalition of the Good-Hearted Engineers +// FREE TO USE TO CONNECT THE WORLD +// --------------------------------------------------------------- + +namespace Taarafo.Portal.Web.Models.Views.Components.PostComponents +{ + public enum PostRemoveComponentState + { + Loading, + Content, + Error + } +} diff --git a/Taarafo.Portal.Web/Views/Components/PostComponents/PostRemoveComponent.razor b/Taarafo.Portal.Web/Views/Components/PostComponents/PostRemoveComponent.razor new file mode 100644 index 0000000..dbbd06a --- /dev/null +++ b/Taarafo.Portal.Web/Views/Components/PostComponents/PostRemoveComponent.razor @@ -0,0 +1,21 @@ +@using PrettyBlazor +@using Taarafo.Portal.Web.Views.Bases +@using Taarafo.Portal.Web.Models.Views.Components.PostComponents + + + + await RemovePostAsync()) /> + + + + + + + + + + \ No newline at end of file diff --git a/Taarafo.Portal.Web/Views/Components/PostComponents/PostRemoveComponent.razor.cs b/Taarafo.Portal.Web/Views/Components/PostComponents/PostRemoveComponent.razor.cs new file mode 100644 index 0000000..4f86956 --- /dev/null +++ b/Taarafo.Portal.Web/Views/Components/PostComponents/PostRemoveComponent.razor.cs @@ -0,0 +1,48 @@ +// --------------------------------------------------------------- +// Copyright (c) Coalition of the Good-Hearted Engineers +// FREE TO USE TO CONNECT THE WORLD +// --------------------------------------------------------------- + +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Taarafo.Portal.Web.Models.PostViews; +using Taarafo.Portal.Web.Models.Views.Components.PostComponents; +using Taarafo.Portal.Web.Services.Views.PostViews; +using Taarafo.Portal.Web.Views.Bases; + +namespace Taarafo.Portal.Web.Views.Components.PostComponents +{ + public partial class PostRemoveComponent : ComponentBase + { + [Inject] + public IPostViewService PostViewService { get; set; } + + [Parameter] + public PostView PostView { get; set; } + + public PostRemoveComponentState State { get; set; } + public ButtonBase Button { get; set; } + public string ErrorMessage { get; set; } + public ImageBase ErrorImage { get; set; } + + protected override void OnInitialized() => + State = PostRemoveComponentState.Content; + + public async ValueTask RemovePostAsync() + { + try + { + Button.Disable(); + + await this.PostViewService + .RemovePostViewByIdAsync(PostView.Id); + } + catch (Exception exception) + { + this.ErrorMessage = exception.Message; + this.State = PostRemoveComponentState.Error; + } + } + } +}