fix(module: select): arrow down click does not auto close (#1977)

* fix(module:select): arrow down click does not auto close

* test case added
This commit is contained in:
Andrzej Bakun 2021-10-11 16:17:14 +02:00 committed by GitHub
parent 45b47d49b6
commit 5c2f48f718
8 changed files with 93 additions and 32 deletions

View File

@ -431,6 +431,7 @@ namespace AntDesign.Internal
protected virtual async Task OnTriggerClick() protected virtual async Task OnTriggerClick()
{ {
_mouseInTrigger = true;
if (IsContainTrigger(TriggerType.Click)) if (IsContainTrigger(TriggerType.Click))
{ {
if (_overlay.IsPopup()) if (_overlay.IsPopup())
@ -446,6 +447,7 @@ namespace AntDesign.Internal
{ {
await Hide(); await Hide();
} }
_mouseInTrigger = false;
} }
protected virtual async Task OnTriggerContextmenu(MouseEventArgs args) protected virtual async Task OnTriggerContextmenu(MouseEventArgs args)

View File

@ -4,6 +4,7 @@
<TargetFrameworks>netcoreapp3.1;net5</TargetFrameworks> <TargetFrameworks>netcoreapp3.1;net5</TargetFrameworks>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<LangVersion>9.0</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,8 +1,10 @@
using System; using System;
using System.Globalization; using System.Globalization;
using AntDesign.JsInterop;
using Bunit; using Bunit;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Moq;
namespace AntDesign.Tests namespace AntDesign.Tests
{ {
@ -11,12 +13,14 @@ namespace AntDesign.Tests
public TestContext Context => this; public TestContext Context => this;
public NavigationManager NavigationManager => Services.GetRequiredService<NavigationManager>(); public NavigationManager NavigationManager => Services.GetRequiredService<NavigationManager>();
public AntDesignTestBase() public Mock<IDomEventListener> MockedDomEventListener { get; set; } = new Mock<IDomEventListener>();
public AntDesignTestBase(bool useMoq = false)
{ {
Services.AddAntDesign(); Services.AddAntDesign();
//Needed for Tests using Overlay //Needed for Tests using Overlay
Services.AddScoped<AntDesign.JsInterop.DomEventService>(sp => new TestDomEventService(Context.JSInterop.JSRuntime)); Services.AddScoped<AntDesign.JsInterop.DomEventService>(sp => new TestDomEventService(Context.JSInterop.JSRuntime, MockedDomEventListener));
JSInterop.SetupVoid(JSInteropConstants.OverlayComponentHelper.DeleteOverlayFromContainer, _ => true); JSInterop.SetupVoid(JSInteropConstants.OverlayComponentHelper.DeleteOverlayFromContainer, _ => true);
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo("en-US"); CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo("en-US");

View File

@ -9,19 +9,24 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using AntDesign.JsInterop; using AntDesign.JsInterop;
using Microsoft.JSInterop; using Microsoft.JSInterop;
using Moq;
namespace AntDesign.Tests namespace AntDesign.Tests
{ {
public class TestDomEventService : AntDesign.JsInterop.DomEventService public class TestDomEventService : AntDesign.JsInterop.DomEventService
{ {
public TestDomEventService(IJSRuntime js) : base(js) public Mock<IDomEventListener> MockedDomEventListener { get; set; }
public TestDomEventService(IJSRuntime js, Mock<IDomEventListener> mock = null) : base(js)
{ {
if (mock is not null)
{
MockedDomEventListener = mock;
}
} }
public override IDomEventListener CreateDomEventListerner() public override IDomEventListener CreateDomEventListerner()
{ {
return new TestDomEventListerner(); return MockedDomEventListener?.Object ?? new TestDomEventListerner();
} }
} }
} }

View File

@ -0,0 +1,76 @@
@using AntDesign.Core.JsInterop.Modules.Components
@using System.ComponentModel.DataAnnotations
@using System.Text.Json
@inherits AntDesignTestBase
@code {
enum City
{
[Display(Name = "Shanghai City")]
Shanghai,
Zhejiang,
Beijing,
}
public Select_Render_Tests()
{
JSInterop.Setup<AntDesign.JsInterop.DomRect>(JSInteropConstants.GetBoundingClientRect, _ => true)
.SetResult(new AntDesign.JsInterop.DomRect());
}
[Fact]
public void Render_enum_select()
{
//Arrange
var cut = Render<EnumSelect<City>>(
@<EnumSelect TEnum="City"></EnumSelect>
);
var options = cut.FindAll(".ant-select-item-option-content");
Assert.Equal(3, options.Count);
Assert.Equal("Shanghai City", options[0].TextContent.Trim('\n').Trim());
Assert.Equal("Zhejiang", options[1].TextContent.Trim());
Assert.Equal("Beijing", options[2].TextContent.Trim());
}
[Fact] //covers scenario from issue #1989
public async Task Render_select_dropdown_on_arrow_click()
{
#if !NET6_0_OR_GREATER
JSInterop.SetupVoid(JSInteropConstants.Focus, _ => true).SetVoidResult();;
#endif
JSInterop.Setup<OverlayPosition>(JSInteropConstants.OverlayComponentHelper.AddOverlayToContainer, _ => true)
.SetResult(new OverlayPosition() { Top = 0, Left = 0, ZIndex = 5000, Placement = Placement.BottomLeft });
var mock = base.MockedDomEventListener;
Action<JsonElement>? onMouseUpCallback = default;
mock.Setup(s => s.AddShared<JsonElement>("document", "mouseup", It.IsAny<Action<JsonElement>>(), It.IsAny<bool>()))
.Callback((object dom, string eventName, Action<JsonElement> callback, bool preventDefault) =>
{
if (callback.Target is AntDesign.Internal.OverlayTrigger)
{
onMouseUpCallback = callback;
}
});
var plannedInvocation = JSInterop.Setup<string>(JSInteropConstants.AddDomEventListener, _ => true);
var cut = Render<EnumSelect<City>>(@<EnumSelect TEnum="City"></EnumSelect>);
//Act
var arrow = cut.Find("span.ant-select-arrow");
onMouseUpCallback.Should().NotBeNull();
await cut.InvokeAsync(() => arrow.Click());
cut.WaitForState(() => !cut.Find("div.ant-select-dropdown").ClassList.Contains("ant-select-dropdown-hidden"));
await cut.InvokeAsync(() => onMouseUpCallback?.Invoke(default));
//This is probably not the best solution. However this test is awkward - we are testing
//for something that should not appear. In failing scenarios it appears after some
//time (due to multiple async/await and re-renderings). That actually points to
//a probable wrong design in the way the OverlayTrigger & Overlay are functioning.
//So here we wait and hope the delay is going be long enough for the component
//to finish all its renderings.
await Task.Delay(500);
//Assert
var dropdown = cut.Find("div.ant-select-dropdown");
dropdown.ClassList.Should().NotContain("ant-select-dropdown-hidden");
}
}

View File

@ -1,27 +0,0 @@
@using System.ComponentModel.DataAnnotations
@inherits AntDesignTestBase
@code {
enum City
{
[Display(Name = "Shanghai City")]
Shanghai,
Zhejiang,
Beijing,
}
[Fact]
public void Render_enum_select()
{
//Arrange
JSInterop.Setup<AntDesign.JsInterop.DomRect>(JSInteropConstants.GetBoundingClientRect, _ => true)
.SetResult(new AntDesign.JsInterop.DomRect());
var cut = Render<EnumSelect<City>>(@<EnumSelect TEnum="City"></EnumSelect> );
var options = cut.FindAll(".ant-select-item-option-content");
Assert.Equal(3, options.Count);
Assert.Equal("Shanghai City", options[0].TextContent.Trim('\n').Trim());
Assert.Equal("Zhejiang", options[1].TextContent.Trim());
Assert.Equal("Beijing", options[2].TextContent.Trim());
}
}