From 00533bd46206a6f0de4516b65645b511a74efd8f Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sun, 22 Oct 2023 19:21:41 +0300 Subject: [PATCH 1/7] add links --- .../Client/Pages/AspectRatio/AspectRatioPage.razor | 4 ++-- .../Client/Pages/BasicUsage/BasicCropperUsagePage.razor | 2 +- .../Pages/CropBoxDimensions/CropBoxDimensionsPage.razor | 6 +++--- .../Client/Pages/CropZoom/CropperZoomPage.razor | 6 +++--- .../Client/Pages/ViewModes/ViewModesPage.razor | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor b/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor index 64bb04f8..35ce43c1 100644 --- a/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor +++ b/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor @@ -23,7 +23,7 @@ You can use AspectRatio decimal field in the - Option property to define the fixed aspect ratio of the crop box. + Options property to define the fixed aspect ratio of the crop box.

To enable free aspect ratio setting AspectRatio propety to 0. @@ -54,7 +54,7 @@ Use InitialAspectRatio in the - Option cropper component property + Options cropper component property to define the initial aspect ratio of the crop box.

By default, it is the same as the aspect ratio of the canvas (image wrapper). diff --git a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor index 2d6beae0..863adb8a 100644 --- a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor +++ b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor @@ -16,7 +16,7 @@ To start using the cropper component, you must specify the path to the image with which you will work in the Src property. - You also need to specify the cropper settings using the Options property, + You also need to specify the cropper settings using the Options property, which can be left as default, as in the example below.
diff --git a/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor b/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor index 09324bde..f9cfe5a3 100644 --- a/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor +++ b/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor @@ -10,14 +10,14 @@ To set the initial dimensions of crop area (crop box), you can use the SetDataOptions property, - which is located in the Option property of the cropper. + which is located in the Options property of the cropper.

To resize the crop area of ​​an already initialized cropper component you can use its SetData method.
Note: This method only available when the value of the - ViewMode option is greater than or equal to 1. + ViewMode option is greater than or equal to 1. Height and width of the crop area are based on the natural size of the original image. @@ -53,7 +53,7 @@ Use the MinCropBoxHeight and MinCropBoxWidth - fields in the Option cropper component property to + fields in the Options cropper component property to enable minimum limit for the relative size of crop area
diff --git a/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor b/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor index 830a708e..a0d90920 100644 --- a/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor +++ b/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor @@ -19,10 +19,10 @@ You can use Zoomable boolean field in the - Option property to enable/disable to zoom the image. + Options property to enable/disable to zoom the image.

You can use ZoomOnTouch boolean field in the - Option property to enable/disable to + Options property to enable/disable to zoom the image by dragging touch.

Boolean field ZoomOnWheel used to enable/disable @@ -38,7 +38,7 @@ Use decimal field WheelZoomRatio in the - Option cropper component property + Options cropper component property to define zoom ratio when zooming the image by mouse wheeling.

By default, WheelZoomRatio is 0,1. diff --git a/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor b/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor index 4b260bf7..da02264d 100644 --- a/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor +++ b/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor @@ -8,7 +8,7 @@ - With the ViewMode in Options prop + With the ViewMode in Options prop you can change the view mode of the cropper.

ViewMode enumeration contains the following view modes: @@ -34,14 +34,14 @@
- If you set ViewMode to ViewMode. + If you set ViewMode to ViewMode. Vm0, the crop box can extend outside the canvas, while a value of Vm1, Vm2, or Vm3 will restrict the crop box to the size of the canvas. - ViewMode of Vm2 or Vm3 + ViewMode of Vm2 or Vm3 will additionally restrict the canvas to the container.
There is no difference between Vm2 and Vm3 From 8e937a0a789bc5ea24d95a28b1aaf8b04b9a61e3 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sun, 22 Oct 2023 19:33:44 +0300 Subject: [PATCH 2/7] fix security: prevent phishing attacks --- src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor | 1 + .../Client/Pages/AspectRatio/AspectRatioPage.razor | 4 ++-- .../Client/Pages/BasicUsage/BasicCropperUsagePage.razor | 6 +++--- .../Pages/CropBoxDimensions/CropBoxDimensionsPage.razor | 6 +++--- .../Client/Pages/CropZoom/CropperZoomPage.razor | 6 +++--- .../Client/Pages/ViewModes/ViewModesPage.razor | 6 +++--- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor b/src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor index 9072c262..3ae611ce 100644 --- a/src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor +++ b/src/Cropper.Blazor/Client/Components/Docs/DocsApi.razor @@ -19,6 +19,7 @@
  • @Type.GetTypeDisplayName() diff --git a/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor b/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor index 35ce43c1..58b8b66f 100644 --- a/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor +++ b/src/Cropper.Blazor/Client/Pages/AspectRatio/AspectRatioPage.razor @@ -23,7 +23,7 @@ You can use AspectRatio decimal field in the - Options property to define the fixed aspect ratio of the crop box. + Options property to define the fixed aspect ratio of the crop box.

    To enable free aspect ratio setting AspectRatio propety to 0. @@ -54,7 +54,7 @@ Use InitialAspectRatio in the - Options cropper component property + Options cropper component property to define the initial aspect ratio of the crop box.

    By default, it is the same as the aspect ratio of the canvas (image wrapper). diff --git a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor index 863adb8a..b3bea68f 100644 --- a/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor +++ b/src/Cropper.Blazor/Client/Pages/BasicUsage/BasicCropperUsagePage.razor @@ -8,7 +8,7 @@ Note The CropperComponent is dependant on ICropperComponentBase - Check the Installation page for instructions regarding default setup. + Check the Installation page for instructions regarding default setup. @@ -16,8 +16,8 @@ To start using the cropper component, you must specify the path to the image with which you will work in the Src property. - You also need to specify the cropper settings using the Options property, - which can be left as default, as in the example below. + You also need to specify the cropper settings using the Options property, + which can be left as default, as in the example below.
    Note: With the release of .NET 8, сropper's default settings will be set automatically, diff --git a/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor b/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor index f9cfe5a3..8f6215c2 100644 --- a/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor +++ b/src/Cropper.Blazor/Client/Pages/CropBoxDimensions/CropBoxDimensionsPage.razor @@ -10,14 +10,14 @@ To set the initial dimensions of crop area (crop box), you can use the SetDataOptions property, - which is located in the Options property of the cropper. + which is located in the Options property of the cropper.

    To resize the crop area of ​​an already initialized cropper component you can use its SetData method.
    Note: This method only available when the value of the - ViewMode option is greater than or equal to 1. + ViewMode option is greater than or equal to 1. Height and width of the crop area are based on the natural size of the original image. @@ -53,7 +53,7 @@ Use the MinCropBoxHeight and MinCropBoxWidth - fields in the Options cropper component property to + fields in the Options cropper component property to enable minimum limit for the relative size of crop area
    diff --git a/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor b/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor index a0d90920..9d21193a 100644 --- a/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor +++ b/src/Cropper.Blazor/Client/Pages/CropZoom/CropperZoomPage.razor @@ -19,10 +19,10 @@ You can use Zoomable boolean field in the - Options property to enable/disable to zoom the image. + Options property to enable/disable to zoom the image.

    You can use ZoomOnTouch boolean field in the - Options property to enable/disable to + Options property to enable/disable to zoom the image by dragging touch.

    Boolean field ZoomOnWheel used to enable/disable @@ -38,7 +38,7 @@ Use decimal field WheelZoomRatio in the - Options cropper component property + Options cropper component property to define zoom ratio when zooming the image by mouse wheeling.

    By default, WheelZoomRatio is 0,1. diff --git a/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor b/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor index da02264d..672ee524 100644 --- a/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor +++ b/src/Cropper.Blazor/Client/Pages/ViewModes/ViewModesPage.razor @@ -8,7 +8,7 @@ - With the ViewMode in Options prop + With the ViewMode in Options prop you can change the view mode of the cropper.

    ViewMode enumeration contains the following view modes: @@ -34,14 +34,14 @@
    - If you set ViewMode to ViewMode. + If you set ViewMode to ViewMode. Vm0, the crop box can extend outside the canvas, while a value of Vm1, Vm2, or Vm3 will restrict the crop box to the size of the canvas. - ViewMode of Vm2 or Vm3 + ViewMode of Vm2 or Vm3 will additionally restrict the canvas to the container.
    There is no difference between Vm2 and Vm3 From 694c479f950eba6609b546d7b8c1fd956ee6866f Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sun, 22 Oct 2023 20:08:59 +0300 Subject: [PATCH 3/7] increase coverage unit tests, fix grammar naming --- README.md | 2 +- .../Client/Pages/CropperDemo.razor | 2 +- .../Client/Pages/CropperDemo.razor.cs | 14 +++---- .../Components/CropperComponent_Should.cs | 12 +++--- .../CropEndEvent/CropEndEvent_Should.cs | 40 ++++++++++++------ .../CropMoveEvent/CropMoveEvent_Should.cs | 40 ++++++++++++------ .../CropStartEvent/CropStartEvent_Should.cs | 40 ++++++++++++------ .../Events/ZoomEvent/ZoomEvent_Should.cs | 40 ++++++++++++------ .../Models/CroppedCanvas_Should.cs | 40 ++++++++++++------ .../Components/CropperComponent.razor.cs | 42 +++++++++---------- 10 files changed, 171 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index afe9b873..0b37067f 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ And then use it in Razor file ([for example](https://github.com/CropperBlazor/Cr IsErrorLoadImage="@IsErrorLoadImage" OnErrorLoadImageEvent="OnErrorLoadImageEvent" Options="Options" - IsAvaibleInitCropper="IsAvaibleInitCropper"> + IsAvailableInitCropper="IsAvailableInitCropper"> ``` diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor index 43231c15..6ded163a 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor @@ -35,7 +35,7 @@ IsErrorLoadImage="@IsErrorLoadImage" OnErrorLoadImageEvent="OnErrorLoadImageEvent" Options="Options" - IsAvaibleInitCropper="IsAvaibleInitCropper" /> + IsAvailableInitCropper="IsAvailableInitCropper" /> diff --git a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs index 17ba0eec..7964c212 100644 --- a/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs +++ b/src/Cropper.Blazor/Client/Pages/CropperDemo.razor.cs @@ -1,4 +1,6 @@ -using Cropper.Blazor.Client.Components; +using System.Reflection; +using System.Text.Json; +using Cropper.Blazor.Client.Components; using Cropper.Blazor.Client.Enums; using Cropper.Blazor.Components; using Cropper.Blazor.Events; @@ -14,8 +16,6 @@ using Microsoft.JSInterop; using MudBlazor; using MudBlazor.Services; -using System.Reflection; -using System.Text.Json; using ErrorEventArgs = Microsoft.AspNetCore.Components.Web.ErrorEventArgs; namespace Cropper.Blazor.Client.Pages @@ -38,7 +38,7 @@ public partial class CropperDemo : IDisposable private string Src = "https://fengyuanchen.github.io/cropperjs/v2/picture.jpg"; private bool IsErrorLoadImage { get; set; } = false; - private bool IsAvaibleInitCropper { get; set; } = true; + private bool IsAvailableInitCropper { get; set; } = true; private readonly string _errorLoadImageSrc = "not-found-image.jpg"; private Breakpoint Start; private Guid SubscriptionId; @@ -392,7 +392,7 @@ public async Task InputFileChangeAsync(InputFileChangeEventArgs inputFileChangeE Src = await CropperComponent!.GetImageUsingStreamingAsync(imageFile, imageFile.Size); - IsAvaibleInitCropper = true; + IsAvailableInitCropper = true; IsErrorLoadImage = false; CropperComponent?.Destroy(); @@ -411,12 +411,12 @@ public async Task ReplaceImageAsync(InputFileChangeEventArgs inputFileChangeEven if (IsErrorLoadImage) { - IsAvaibleInitCropper = true; + IsAvailableInitCropper = true; IsErrorLoadImage = false; } else { - IsAvaibleInitCropper = false; + IsAvailableInitCropper = false; } CropperComponent?.ReplaceAsync(src); diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index e5cc633d..b8a90f42 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -272,8 +272,8 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() ComponentParameter isErrorLoadImageParameter = ComponentParameter.CreateParameter( nameof(CropperComponent.IsErrorLoadImage), false); - ComponentParameter isAvaibleInitCropperParameter = ComponentParameter.CreateParameter( - nameof(CropperComponent.IsAvaibleInitCropper), + ComponentParameter isAvailableInitCropperParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.IsAvailableInitCropper), true); ComponentParameter onLoadImageParameter = ComponentParameter.CreateParameter( nameof(CropperComponent.OnLoadImageEvent), @@ -347,7 +347,7 @@ public async Task Should_Render_CropperComponent_SuccessfulAsync() loadingParameter, errorLoadImageSrcParameter, isErrorLoadImageParameter, - isAvaibleInitCropperParameter, + isAvailableInitCropperParameter, srcParameter, imageClassParameter, onLoadImageParameter, @@ -597,8 +597,8 @@ public void Should_Not_Render_CropperComponent_With_IsNotAvaibleInitCropper_Para ComponentParameter isErrorLoadImage = ComponentParameter.CreateParameter( nameof(CropperComponent.IsErrorLoadImage), true); - ComponentParameter isAvaibleInitCropperParameter = ComponentParameter.CreateParameter( - nameof(CropperComponent.IsAvaibleInitCropper), + ComponentParameter isAvailableInitCropperParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.IsAvailableInitCropper), false); // act @@ -608,7 +608,7 @@ public void Should_Not_Render_CropperComponent_With_IsNotAvaibleInitCropper_Para loadingParameter, errorLoadImageSrcParameter, isErrorLoadImage, - isAvaibleInitCropperParameter); + isAvailableInitCropperParameter); // assert IElement expectedElement = cropperComponent.Find($"img.{errorLoadImageClass}"); diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropEndEvent/CropEndEvent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropEndEvent/CropEndEvent_Should.cs index 69d48e69..1f0b5efc 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropEndEvent/CropEndEvent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropEndEvent/CropEndEvent_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Microsoft.JSInterop; using Moq; using Xunit; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Events.CropEndEvent { public class CropEndEvent_Should { - private readonly Mock _mockIJSObjectReference; - private readonly Event _event; + private static Mock _mockIJSObjectReference = null!; - public CropEndEvent_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _event = new Faker() - .RuleFor(x => x.OriginalEvent, _mockIJSObjectReference.Object); - } + // arrange + Event @event = new Faker() + .RuleFor(x => x.OriginalEvent, jSObjectReference); - [Fact] - public void Verify_Dispose() - { // act - _event.Dispose(); + @event.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropMoveEvent/CropMoveEvent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropMoveEvent/CropMoveEvent_Should.cs index 2d84321a..79cc67cd 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropMoveEvent/CropMoveEvent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropMoveEvent/CropMoveEvent_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Microsoft.JSInterop; using Moq; using Xunit; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Events.CropMoveEvent { public class CropMoveEvent_Should { - private readonly Mock _mockIJSObjectReference; - private readonly Event _event; + private static Mock _mockIJSObjectReference = null!; - public CropMoveEvent_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _event = new Faker() - .RuleFor(x => x.OriginalEvent, _mockIJSObjectReference.Object); - } + // arrange + Event @event = new Faker() + .RuleFor(x => x.OriginalEvent, jSObjectReference); - [Fact] - public void Verify_Dispose() - { // act - _event.Dispose(); + @event.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropStartEvent/CropStartEvent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropStartEvent/CropStartEvent_Should.cs index 70d8d8c0..47471089 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropStartEvent/CropStartEvent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/CropStartEvent/CropStartEvent_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Microsoft.JSInterop; using Moq; using Xunit; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Events.CropStartEvent { public class CropStartEvent_Should { - private readonly Mock _mockIJSObjectReference; - private readonly Event _event; + private static Mock _mockIJSObjectReference = null!; - public CropStartEvent_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _event = new Faker() - .RuleFor(x => x.OriginalEvent, _mockIJSObjectReference.Object); - } + // arrange + Event @event = new Faker() + .RuleFor(x => x.OriginalEvent, jSObjectReference); - [Fact] - public void Verify_Dispose() - { // act - _event.Dispose(); + @event.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/ZoomEvent/ZoomEvent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/ZoomEvent/ZoomEvent_Should.cs index d2328ee9..e79499b5 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/ZoomEvent/ZoomEvent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Events/ZoomEvent/ZoomEvent_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Microsoft.JSInterop; using Moq; using Xunit; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Events.ZoomEvent { public class ZoomEvent_Should { - private readonly Mock _mockIJSObjectReference; - private readonly Event _event; + private static Mock _mockIJSObjectReference = null!; - public ZoomEvent_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _event = new Faker() - .RuleFor(x => x.OriginalEvent, _mockIJSObjectReference.Object); - } + // arrange + Event @event = new Faker() + .RuleFor(x => x.OriginalEvent, jSObjectReference); - [Fact] - public void Verify_Dispose() - { // act - _event.Dispose(); + @event.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/CroppedCanvas_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/CroppedCanvas_Should.cs index 1a2143ab..041d4525 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/CroppedCanvas_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Models/CroppedCanvas_Should.cs @@ -1,4 +1,5 @@ -using Bogus; +using System.Collections.Generic; +using Bogus; using Cropper.Blazor.Models; using Microsoft.JSInterop; using Moq; @@ -8,24 +9,37 @@ namespace Cropper.Blazor.UnitTests.Models { public class CroppedCanvas_Should { - private readonly Mock _mockIJSObjectReference; - private readonly CroppedCanvas _croppedCanvas; + private static Mock _mockIJSObjectReference = null!; - public CroppedCanvas_Should() + [Theory, MemberData(nameof(TestData_Verify_Dispose))] + public void Verify_Dispose(IJSObjectReference? jSObjectReference, Times times) { - _mockIJSObjectReference = new Mock(); - _croppedCanvas = new Faker() - .CustomInstantiator(f => new CroppedCanvas(_mockIJSObjectReference.Object)); - } + // arrange + CroppedCanvas croppedCanvas = new Faker() + .CustomInstantiator(f => new CroppedCanvas(jSObjectReference)); - [Fact] - public void Verify_Dispose() - { // act - _croppedCanvas.Dispose(); + croppedCanvas.Dispose(); // assert - _mockIJSObjectReference.Verify(c => c.DisposeAsync(), Times.Once()); + _mockIJSObjectReference.Verify(c => c.DisposeAsync(), times); + } + + public static IEnumerable TestData_Verify_Dispose() + { + yield return WrapArgs(null, Times.Never()); + + _mockIJSObjectReference = new Mock(); + yield return WrapArgs(_mockIJSObjectReference.Object, Times.Once()); + + static object[] WrapArgs( + IJSObjectReference? jSObjectReference, + Times times) + => new object[] + { + jSObjectReference, + times + }; } } } diff --git a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs index b6808d58..4d186fd0 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Components/CropperComponent.razor.cs @@ -72,7 +72,7 @@ public partial class CropperComponent : ICropperComponentBase, IAsyncDisposable, /// In addition, it should be used to disable re-initialization (replace image) of cropper after successful image load when set to false. /// [Parameter] - public bool IsAvaibleInitCropper { get; set; } = true; + public bool IsAvailableInitCropper { get; set; } = true; /// /// User class names, separated by space. @@ -177,7 +177,7 @@ protected override void OnInitialized() /// private void OnLoadImage(ProgressEventArgs progressEventArgs) { - if (IsAvaibleInitCropper) + if (IsAvailableInitCropper) { InitCropper(); } @@ -270,7 +270,7 @@ public void IsReady(JSEventData jSEventData) /// The used to propagate notifications that the operation should be canceled. public void SetDragMode(DragMode dragMode, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetDragModeAsync(CropperComponentId, dragMode, cancellationToken); + CropperJsIntertop!.SetDragModeAsync(CropperComponentId, dragMode, cancellationToken); } /// @@ -284,7 +284,7 @@ public void SetDragMode(DragMode dragMode, CancellationToken cancellationToken = /// The used to propagate notifications that the operation should be canceled. public void Zoom(decimal ratio, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ZoomAsync(CropperComponentId, ratio, cancellationToken); + CropperJsIntertop!.ZoomAsync(CropperComponentId, ratio, cancellationToken); } /// @@ -296,7 +296,7 @@ public void Zoom(decimal ratio, CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void ZoomTo(decimal ratio, decimal pivotX, decimal pivotY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ZoomToAsync(CropperComponentId, ratio, pivotX, pivotY, cancellationToken); + CropperJsIntertop!.ZoomToAsync(CropperComponentId, ratio, pivotX, pivotY, cancellationToken); } /// @@ -307,7 +307,7 @@ public void ZoomTo(decimal ratio, decimal pivotX, decimal pivotY, CancellationTo /// The used to propagate notifications that the operation should be canceled. public void Move(decimal offsetX, decimal? offsetY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.MoveAsync(CropperComponentId, offsetX, offsetY, cancellationToken); + CropperJsIntertop!.MoveAsync(CropperComponentId, offsetX, offsetY, cancellationToken); } /// @@ -318,7 +318,7 @@ public void Move(decimal offsetX, decimal? offsetY, CancellationToken cancellati /// The used to propagate notifications that the operation should be canceled. public void MoveTo(decimal x, decimal? y, CancellationToken cancellationToken = default) { - CropperJsIntertop?.MoveToAsync(CropperComponentId, x, y, cancellationToken); + CropperJsIntertop!.MoveToAsync(CropperComponentId, x, y, cancellationToken); } /// @@ -332,7 +332,7 @@ public void MoveTo(decimal x, decimal? y, CancellationToken cancellationToken = /// The used to propagate notifications that the operation should be canceled. public void Rotate(decimal degree, CancellationToken cancellationToken = default) { - CropperJsIntertop?.RotateAsync(CropperComponentId, degree, cancellationToken); + CropperJsIntertop!.RotateAsync(CropperComponentId, degree, cancellationToken); } /// @@ -346,7 +346,7 @@ public void Rotate(decimal degree, CancellationToken cancellationToken = default /// The used to propagate notifications that the operation should be canceled. public void ScaleX(decimal scaleX, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ScaleXAsync(CropperComponentId, scaleX, cancellationToken); + CropperJsIntertop!.ScaleXAsync(CropperComponentId, scaleX, cancellationToken); } /// @@ -360,7 +360,7 @@ public void ScaleX(decimal scaleX, CancellationToken cancellationToken = default /// The used to propagate notifications that the operation should be canceled. public void ScaleY(decimal scaleY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ScaleYAsync(CropperComponentId, scaleY, cancellationToken); + CropperJsIntertop!.ScaleYAsync(CropperComponentId, scaleY, cancellationToken); } /// @@ -379,7 +379,7 @@ public void ScaleY(decimal scaleY, CancellationToken cancellationToken = default /// The used to propagate notifications that the operation should be canceled. public void Scale(decimal scaleX, decimal scaleY, CancellationToken cancellationToken = default) { - CropperJsIntertop?.ScaleAsync(CropperComponentId, scaleX, scaleY, cancellationToken); + CropperJsIntertop!.ScaleAsync(CropperComponentId, scaleX, scaleY, cancellationToken); } /// @@ -388,7 +388,7 @@ public void Scale(decimal scaleX, decimal scaleY, CancellationToken cancellation /// The used to propagate notifications that the operation should be canceled. public void Crop(CancellationToken cancellationToken = default) { - CropperJsIntertop?.CropAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.CropAsync(CropperComponentId, cancellationToken); } /// @@ -397,7 +397,7 @@ public void Crop(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Clear(CancellationToken cancellationToken = default) { - CropperJsIntertop?.ClearAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.ClearAsync(CropperComponentId, cancellationToken); } /// @@ -406,7 +406,7 @@ public void Clear(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Enable(CancellationToken cancellationToken = default) { - CropperJsIntertop?.EnableAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.EnableAsync(CropperComponentId, cancellationToken); } /// @@ -415,7 +415,7 @@ public void Enable(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Disable(CancellationToken cancellationToken = default) { - CropperJsIntertop?.DisableAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.DisableAsync(CropperComponentId, cancellationToken); } /// @@ -424,7 +424,7 @@ public void Disable(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Reset(CancellationToken cancellationToken = default) { - CropperJsIntertop?.ResetAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.ResetAsync(CropperComponentId, cancellationToken); } /// @@ -433,7 +433,7 @@ public void Reset(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void Destroy(CancellationToken cancellationToken = default) { - CropperJsIntertop?.DestroyAsync(CropperComponentId, cancellationToken); + CropperJsIntertop!.DestroyAsync(CropperComponentId, cancellationToken); } /// @@ -443,7 +443,7 @@ public void Destroy(CancellationToken cancellationToken = default) /// The used to propagate notifications that the operation should be canceled. public void SetAspectRatio(decimal aspectRatio, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetAspectRatioAsync(CropperComponentId, aspectRatio, cancellationToken); + CropperJsIntertop!.SetAspectRatioAsync(CropperComponentId, aspectRatio, cancellationToken); } /// @@ -453,7 +453,7 @@ public void SetAspectRatio(decimal aspectRatio, CancellationToken cancellationTo /// The used to propagate notifications that the operation should be canceled. public void SetCropBoxData(SetCropBoxDataOptions cropBoxDataOptions, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetCropBoxDataAsync(CropperComponentId, cropBoxDataOptions, cancellationToken); + CropperJsIntertop!.SetCropBoxDataAsync(CropperComponentId, cropBoxDataOptions, cancellationToken); } /// @@ -463,7 +463,7 @@ public void SetCropBoxData(SetCropBoxDataOptions cropBoxDataOptions, Cancellatio /// The used to propagate notifications that the operation should be canceled. public void SetData(SetDataOptions setDataOptions, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetDataAsync(CropperComponentId, setDataOptions, cancellationToken); + CropperJsIntertop!.SetDataAsync(CropperComponentId, setDataOptions, cancellationToken); } /// @@ -473,7 +473,7 @@ public void SetData(SetDataOptions setDataOptions, CancellationToken cancellatio /// The used to propagate notifications that the operation should be canceled. public void SetCanvasData(SetCanvasDataOptions setCanvasDataOptions, CancellationToken cancellationToken = default) { - CropperJsIntertop?.SetCanvasDataAsync(CropperComponentId, setCanvasDataOptions, cancellationToken); + CropperJsIntertop!.SetCanvasDataAsync(CropperComponentId, setCanvasDataOptions, cancellationToken); } /// From c9692eb9d85d0a02925481b8dea62b0dce8afb2f Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sun, 22 Oct 2023 20:59:20 +0300 Subject: [PATCH 4/7] improve coverage --- .../Components/CropperComponent_Should.cs | 72 +++++++++++++++++++ .../Extensions/ServiceCollectionExtensions.cs | 6 +- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index b8a90f42..eeae8298 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -650,6 +650,78 @@ public void Verify_Method_To_Be_Invokable_From_JS(string methodName) attribute.Should().NotBeNull(); } + [Fact] + public async Task Should_Render_CropperComponent_Without_Action_Parameters_SuccessfulAsync() + { + // arrange + CancellationToken cancellationToken = new(); + ProgressEventArgs progressEventArgs = new Faker() + .Generate(); + Options options = new Faker() + .Generate(); + ErrorEventArgs errorEventArgs = new Faker() + .Generate(); + JSEventData zoomEvent = new Faker>() + .Generate(); + JSEventData cropStartEvent = new Faker>() + .Generate(); + JSEventData cropMoveEvent = new Faker>() + .Generate(); + JSEventData cropEndEvent = new Faker>() + .Generate(); + JSEventData cropEvent = new Faker>() + .Generate(); + + ComponentParameter optionsParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.Options), + options); + ComponentParameter onLoadImageParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.OnLoadImageEvent), + null); + ComponentParameter onErrorLoadImageParameter = ComponentParameter.CreateParameter( + nameof(CropperComponent.OnErrorLoadImageEvent), + null); + + // act + IRenderedComponent cropperComponent = _testContext + .RenderComponent( + optionsParameter, + onLoadImageParameter, + onErrorLoadImageParameter); + + // assert + IElement expectedElement = cropperComponent.Find($"img"); + ElementReference elementReference = (ElementReference)cropperComponent.Instance + .GetInstanceField("ImageReference"); + Guid cropperComponentId = (Guid)cropperComponent.Instance + .GetInstanceField("CropperComponentId"); + + _mockCropperJsInterop.Verify(c => c.LoadModuleAsync(cancellationToken), Times.Once()); + elementReference.Id.Should().NotBeNullOrEmpty(); + expectedElement.ClassName.Should().BeNull(); + expectedElement.GetAttribute("src").Should().BeNull(); + expectedElement.GetAttribute("blazor:elementreference").Should().Be(elementReference.Id); + + expectedElement.TriggerEvent("onload", progressEventArgs); + _mockCropperJsInterop.Verify(c => c.InitCropperAsync( + cropperComponentId, + elementReference, + options, + It.IsAny>(), + cancellationToken), Times.Once()); + + expectedElement.TriggerEvent("onerror", errorEventArgs); + + await cropperComponent.InvokeAsync(() => + { + cropperComponent.Instance.CropperIsCroped(cropEvent); + cropperComponent.Instance.CropperIsEnded(cropEndEvent); + cropperComponent.Instance.CropperIsMoved(cropMoveEvent); + cropperComponent.Instance.CropperIsStarted(cropStartEvent); + cropperComponent.Instance.CropperIsZoomed(zoomEvent); + }); + } + public void Dispose() { _testContext.DisposeComponents(); diff --git a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs index 313162a0..3133719a 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using Cropper.Blazor.ModuleOptions; +using System; +using Cropper.Blazor.ModuleOptions; using Cropper.Blazor.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -19,7 +20,8 @@ public static class ServiceCollectionExtensions /// Continues the chain. public static IServiceCollection AddCropper(this IServiceCollection services, CropperJsInteropOptions? cropperJsInteropOptions = null) { - services.AddSingleton(services => cropperJsInteropOptions ?? new CropperJsInteropOptions()); + Func funcServiceProvider = (IServiceProvider serviceProvider) => cropperJsInteropOptions ?? new CropperJsInteropOptions(); + services.AddSingleton(funcServiceProvider); services.TryAddScoped(); From 8686291d2a3a454955e0d05df6df66edab7243c3 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sun, 22 Oct 2023 21:07:46 +0300 Subject: [PATCH 5/7] fix pipeline required coverage --- .github/codecov.yml | 2 +- .../Components/CropperComponent_Should.cs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index 4e94d0ae..1ec0f69f 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -15,7 +15,7 @@ coverage: status: project: default: - target: 90% # the required coverage value + target: 100% # the required coverage value threshold: 0.1% # the leniency in hitting the target patch: default: diff --git a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs index eeae8298..442343bc 100644 --- a/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs +++ b/src/Cropper.Blazor/Cropper.Blazor.UnitTests/Components/CropperComponent_Should.cs @@ -661,6 +661,8 @@ public async Task Should_Render_CropperComponent_Without_Action_Parameters_Succe .Generate(); ErrorEventArgs errorEventArgs = new Faker() .Generate(); + JSEventData cropReadyEvent = new Faker>() + .Generate(); JSEventData zoomEvent = new Faker>() .Generate(); JSEventData cropStartEvent = new Faker>() @@ -714,6 +716,7 @@ public async Task Should_Render_CropperComponent_Without_Action_Parameters_Succe await cropperComponent.InvokeAsync(() => { + cropperComponent.Instance.IsReady(cropReadyEvent); cropperComponent.Instance.CropperIsCroped(cropEvent); cropperComponent.Instance.CropperIsEnded(cropEndEvent); cropperComponent.Instance.CropperIsMoved(cropMoveEvent); From 586049dcd72305f39523e85865c3a2f4a297c5b9 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sun, 22 Oct 2023 21:12:33 +0300 Subject: [PATCH 6/7] fix coverage --- .../Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs index 3133719a..9bced276 100644 --- a/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs +++ b/src/Cropper.Blazor/Cropper.Blazor/Extensions/ServiceCollectionExtensions.cs @@ -20,9 +20,10 @@ public static class ServiceCollectionExtensions /// Continues the chain. public static IServiceCollection AddCropper(this IServiceCollection services, CropperJsInteropOptions? cropperJsInteropOptions = null) { - Func funcServiceProvider = (IServiceProvider serviceProvider) => cropperJsInteropOptions ?? new CropperJsInteropOptions(); - services.AddSingleton(funcServiceProvider); + CropperJsInteropOptions? options = cropperJsInteropOptions ?? new CropperJsInteropOptions(); + Func funcServiceProvider = (IServiceProvider serviceProvider) => options; + services.AddSingleton(funcServiceProvider); services.TryAddScoped(); return services; From e71ed5c2bfdef57fb3fa8782a511797fe41f3d95 Mon Sep 17 00:00:00 2001 From: MaxymGorn Date: Sun, 22 Oct 2023 21:29:35 +0300 Subject: [PATCH 7/7] small fix --- src/Cropper.Blazor/Client/Pages/About.razor | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Cropper.Blazor/Client/Pages/About.razor b/src/Cropper.Blazor/Client/Pages/About.razor index 5f00f403..f13c3886 100644 --- a/src/Cropper.Blazor/Client/Pages/About.razor +++ b/src/Cropper.Blazor/Client/Pages/About.razor @@ -1,4 +1,5 @@ @page "/about" +@layout LandingLayout