Skip to content

Globalization test updates #12377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/Components/Blazor/Build/test/BindRazorIntegrationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class MyComponent : ComponentBase
frame => AssertFrame.Attribute(frame, "ValueChanged", typeof(Action<int>), 2));
}

[Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12286")]
[Fact]
public void Render_BindToComponent_SpecifiesValue_WithoutMatchingProperties()
{
// Arrange
Expand Down Expand Up @@ -89,7 +89,7 @@ Task IComponent.SetParametersAsync(ParameterCollection parameters)
frames,
frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0),
frame => AssertFrame.Attribute(frame, "Value", 42, 1),
frame => AssertFrame.Attribute(frame, "ValueChanged", typeof(EventCallback<UIChangeEventArgs>), 2));
frame => AssertFrame.Attribute(frame, "ValueChanged", typeof(EventCallback<int>), 2));
}

[Fact]
Expand Down Expand Up @@ -129,7 +129,7 @@ public class MyComponent : ComponentBase
frame => AssertFrame.Attribute(frame, "OnChanged", typeof(Action<int>), 2));
}

[Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12286")]
[Fact]
public void Render_BindToComponent_SpecifiesValueAndChangeEvent_WithoutMatchingProperties()
{
// Arrange
Expand Down Expand Up @@ -163,7 +163,7 @@ Task IComponent.SetParametersAsync(ParameterCollection parameters)
frames,
frame => AssertFrame.Component(frame, "Test.MyComponent", 3, 0),
frame => AssertFrame.Attribute(frame, "Value", 42, 1),
frame => AssertFrame.Attribute(frame, "OnChanged", typeof(EventCallback<UIChangeEventArgs>), 2));
frame => AssertFrame.Attribute(frame, "OnChanged", typeof(EventCallback<int>), 2));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ protected void NotifyAuthenticationStateChanged(System.Threading.Tasks.Task<Micr
}
[Microsoft.AspNetCore.Components.BindElementAttribute("select", null, "value", "onchange")]
[Microsoft.AspNetCore.Components.BindElementAttribute("textarea", null, "value", "onchange")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("checkbox", null, "checked", "onchange")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("text", null, "value", "onchange")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute(null, "value", "value", "onchange")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute(null, null, "value", "onchange")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("checkbox", null, "checked", "onchange", false, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("date", null, "value", "onchange", true, "yyyy-MM-dd")]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("number", null, "value", "onchange", true, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute("text", null, "value", "onchange", false, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute(null, "value", "value", "onchange", false, null)]
[Microsoft.AspNetCore.Components.BindInputElementAttribute(null, null, "value", "onchange", false, null)]
public static partial class BindAttributes
{
}
Expand Down Expand Up @@ -84,8 +86,10 @@ public BindElementAttribute(string element, string suffix, string valueAttribute
[System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=true)]
public sealed partial class BindInputElementAttribute : System.Attribute
{
public BindInputElementAttribute(string type, string suffix, string valueAttribute, string changeAttribute) { }
public BindInputElementAttribute(string type, string suffix, string valueAttribute, string changeAttribute, bool isInvariantCulture, string format) { }
public string ChangeAttribute { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string Format { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public bool IsInvariantCulture { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string Suffix { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string Type { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string ValueAttribute { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
Expand Down
14 changes: 10 additions & 4 deletions src/Components/Components/src/BindAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,20 @@ namespace Microsoft.AspNetCore.Components

// Handles cases like <input @bind="..." /> - this is a fallback and will be ignored
// when a specific type attribute is applied.
[BindInputElement(null, null, "value", "onchange")]
[BindInputElement(null, null, "value", "onchange", isInvariantCulture: false, format: null)]

// Handles cases like <input @bind-value="..." /> - this is a fallback and will be ignored
// when a specific type attribute is applied.
[BindInputElement(null, "value", "value", "onchange")]
[BindInputElement(null, "value", "value", "onchange", isInvariantCulture: false, format: null)]

[BindInputElement("checkbox", null, "checked", "onchange")]
[BindInputElement("text", null, "value", "onchange")]
[BindInputElement("checkbox", null, "checked", "onchange", isInvariantCulture: false, format: null)]
[BindInputElement("text", null, "value", "onchange", isInvariantCulture: false, format: null)]

// type="number" is invariant culture
[BindInputElement("number", null, "value", "onchange", isInvariantCulture: true, format: null)]

// type="date" is invariant culture with a specific format
[BindInputElement("date", null, "value", "onchange", isInvariantCulture: true, format: "yyyy-MM-dd")]

[BindElement("select", null, "value", "onchange")]
[BindElement("textarea", null, "value", "onchange")]
Expand Down
24 changes: 22 additions & 2 deletions src/Components/Components/src/BindInputElementAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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.Globalization;

namespace Microsoft.AspNetCore.Components
{
Expand All @@ -18,7 +19,13 @@ public sealed class BindInputElementAttribute : Attribute
/// <param name="suffix">The suffix value.</param>
/// <param name="valueAttribute">The name of the value attribute to be bound.</param>
/// <param name="changeAttribute">The name of an attribute that will register an associated change event.</param>
public BindInputElementAttribute(string type, string suffix, string valueAttribute, string changeAttribute)
/// <param name="isInvariantCulture">
/// Determines whether binding will use <see cref="CultureInfo.InvariantCulture" /> or <see cref="CultureInfo.CurrentCulture"/>.
/// </param>
/// <param name="format">
/// An optional format to use when converting values.
/// </param>
public BindInputElementAttribute(string type, string suffix, string valueAttribute, string changeAttribute, bool isInvariantCulture, string format)
{
if (valueAttribute == null)
{
Expand All @@ -34,6 +41,8 @@ public BindInputElementAttribute(string type, string suffix, string valueAttribu
Suffix = suffix;
ValueAttribute = valueAttribute;
ChangeAttribute = changeAttribute;
IsInvariantCulture = isInvariantCulture;
Format = format;
}

/// <summary>
Expand All @@ -55,5 +64,16 @@ public BindInputElementAttribute(string type, string suffix, string valueAttribu
/// Gets the name of an attribute that will register an associated change event.
/// </summary>
public string ChangeAttribute { get; }

/// <summary>
/// Gets a value that determines whether binding will use <see cref="CultureInfo.InvariantCulture" /> or
/// <see cref="CultureInfo.CurrentCulture"/>.
/// </summary>
public bool IsInvariantCulture { get; }

/// <summary>
/// Gets an optional format to use when converting values.
/// </summary>
public string Format { get; }
}
}
12 changes: 6 additions & 6 deletions src/Components/test/E2ETest/Tests/BindTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ public void CanBindTextboxNullableDateTimeOffset()

// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12286")]
[Fact]
public void CanBindTextboxDateTimeWithFormat()
{
var target = Browser.FindElement(By.Id("textbox-datetime-format"));
Expand All @@ -770,11 +770,11 @@ public void CanBindTextboxDateTimeWithFormat()
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));

// Clear textbox; value updates to emtpy because that's what we do for `default` when there's a format
// Clear textbox; value updates to the default
target.Clear();
target.SendKeys("\t");
expected = default;
Browser.Equal(string.Empty, () => target.GetAttribute("value"));
Browser.Equal("01-01", () => target.GetAttribute("value"));
Assert.Equal(expected, DateTime.Parse(boundValue.Text));
Assert.Equal(expected, DateTime.Parse(mirrorValue.GetAttribute("value")));

Expand Down Expand Up @@ -818,7 +818,7 @@ public void CanBindTextboxNullableDateTimeWithFormat()

// For date comparisons, we parse (non-formatted) values to compare them. Client-side and server-side
// Blazor have different formatting behaviour by default.
[Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/12286")]
[Fact]
public void CanBindTextboxDateTimeOffsetWithFormat()
{
var target = Browser.FindElement(By.Id("textbox-datetimeoffset-format"));
Expand All @@ -829,10 +829,10 @@ public void CanBindTextboxDateTimeOffsetWithFormat()
Assert.Equal(expected, DateTimeOffset.Parse(boundValue.Text));
Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")));

// Clear textbox; value updates to emtpy because that's what we do for `default` when there's a format
// Clear textbox; value updates to the default
target.Clear();
expected = default;
Browser.Equal(string.Empty, () => target.GetAttribute("value"));
Browser.Equal("01-01", () => target.GetAttribute("value"));
Assert.Equal(expected, DateTimeOffset.Parse(boundValue.Text));
Assert.Equal(expected, DateTimeOffset.Parse(mirrorValue.GetAttribute("value")));

Expand Down
11 changes: 11 additions & 0 deletions src/Components/test/testassets/BasicTestApp/BindMethods.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Microsoft.AspNetCore.Components
{
// This is a temporary workaround for the fact that public previews of VS look for
// this type. Without this the tooling won't understand bind or event handlers.
//
// This has already gotten better in 16.3 and we look for IComponent rather
// than specific implementation details.
public static class BindMethods
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
<div>
<p>Numbers using bind in number fields</p>
<div>
int: <input type="number" id="input_type_number_int" value="@inputTypeNumberInt.ToString(CultureInfo.InvariantCulture)" @onchange="@EventCallback.Factory.CreateBinder(this, (value) => inputTypeNumberInt = value, inputTypeNumberInt, CultureInfo.InvariantCulture)" />
int: <input type="number" id="input_type_number_int" @bind="inputTypeNumberInt" />
<span id="input_type_number_int_value">@inputTypeNumberInt</span>
</div>
<div>
decimal: <input type="number" id="input_type_number_decimal" value="@inputTypeNumberDecimal.ToString(CultureInfo.InvariantCulture)" @onchange="@EventCallback.Factory.CreateBinder(this, (value) => inputTypeNumberDecimal = value, inputTypeNumberDecimal, CultureInfo.InvariantCulture)"/>
decimal: <input type="number" id="input_type_number_decimal" @bind="inputTypeNumberDecimal" />
<span id="input_type_number_decimal_value">@inputTypeNumberDecimal</span>
</div>
</div>
Expand All @@ -43,12 +43,12 @@
<p>Dates using bind in date fields</p>
<div>
DateTime: <input type="text" id="input_type_date_datetime_extrainput" @bind="inputTypeDateDateTime" />
<input type="date" id="input_type_date_datetime" value="@inputTypeDateDateTime.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)" @onchange="@EventCallback.Factory.CreateBinder(this, (value) => inputTypeDateDateTime = value, inputTypeDateDateTime, "yyyy-MM-dd", CultureInfo.InvariantCulture)" />
<input type="date" id="input_type_date_datetime" @bind="inputTypeDateDateTime" />
<span id="input_type_date_datetime_value">@inputTypeDateDateTime</span>
</div>
<div>
DateTimeOffset: <input type="text" id="input_type_date_datetimeoffset_extrainput" @bind="inputTypeDateDateTimeOffset" />
<input type="date" id="input_type_date_datetimeoffset" value="@inputTypeDateDateTimeOffset.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)" @onchange="@EventCallback.Factory.CreateBinder(this, (value) => inputTypeDateDateTimeOffset = value, inputTypeDateDateTimeOffset, "yyyy-MM-dd", CultureInfo.InvariantCulture)"/>
<input type="date" id="input_type_date_datetimeoffset" @bind="inputTypeDateDateTimeOffset" />
<span id="input_type_date_datetimeoffset_value">@inputTypeDateDateTimeOffset</span>
</div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions src/Components/test/testassets/BasicTestApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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.Globalization;
using Microsoft.AspNetCore.Blazor.Hosting;

namespace BasicTestApp
Expand All @@ -9,6 +10,9 @@ public class Program
{
public static void Main(string[] args)
{
// We want the culture to be en-US so that the tests for bind can work consistently.
CultureInfo.CurrentCulture = new CultureInfo("en-US");

CreateHostBuilder(args).Build().Run();
}

Expand Down
8 changes: 7 additions & 1 deletion src/Components/test/testassets/TestServer/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
Expand Down Expand Up @@ -76,7 +77,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
options.AddSupportedCultures("en-US", "fr-FR");
options.AddSupportedUICultures("en-US", "fr-FR");

// Cookie culture provider is included by default.
// Cookie culture provider is included by default, but we want it to be the only one.
options.RequestCultureProviders.Clear();
options.RequestCultureProviders.Add(new CookieRequestCultureProvider());

// We want the default to be en-US so that the tests for bind can work consistently.
options.SetDefaultCulture("en-US");
});

app.UseRouting();
Expand Down