Skip to content

Commit 610fb90

Browse files
Reliability improvement for input date E2E tests (#35505)
1 parent 3c089fa commit 610fb90

File tree

4 files changed

+33
-51
lines changed

4 files changed

+33
-51
lines changed

src/Components/test/E2ETest/ServerExecutionTests/CircuitGracefulTerminationTests.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ public async Task ReloadingThePage_GracefullyDisconnects_TheCurrentCircuit()
6363
await Task.WhenAny(Task.Delay(10000), GracefulDisconnectCompletionSource.Task);
6464

6565
// Assert
66-
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages);
67-
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages);
66+
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages.ToArray());
67+
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages.ToArray());
6868
}
6969

7070
[Fact]
@@ -76,8 +76,8 @@ public async Task ClosingTheBrowserWindow_GracefullyDisconnects_TheCurrentCircui
7676

7777
// Assert
7878
Assert.True(GracefulDisconnectCompletionSource.Task.IsCompletedSuccessfully);
79-
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages);
80-
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages);
79+
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages.ToArray());
80+
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages.ToArray());
8181
}
8282

8383
[Fact]
@@ -90,8 +90,8 @@ public async Task ClosingTheBrowserWindow_GracefullyDisconnects_WhenNavigatingAw
9090

9191
// Assert
9292
Assert.Equal(GracefulDisconnectCompletionSource.Task, task);
93-
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages);
94-
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages);
93+
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages.ToArray());
94+
Assert.Contains((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages.ToArray());
9595
}
9696

9797
[Fact]
@@ -103,8 +103,8 @@ public async Task NavigatingToProtocolLink_DoesNotGracefullyDisconnect_TheCurren
103103
await Task.WhenAny(Task.Delay(10000), GracefulDisconnectCompletionSource.Task);
104104

105105
// Assert
106-
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages);
107-
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages);
106+
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages.ToArray());
107+
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages.ToArray());
108108
}
109109

110110
[Fact]
@@ -116,8 +116,8 @@ public async Task DownloadAction_DoesNotGracefullyDisconnect_TheCurrentCircuit()
116116
await Task.WhenAny(Task.Delay(10000), GracefulDisconnectCompletionSource.Task);
117117

118118
// Assert
119-
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages);
120-
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages);
119+
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages.ToArray());
120+
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages.ToArray());
121121
}
122122

123123
[Fact]
@@ -129,8 +129,8 @@ public async Task DownloadHref_DoesNotGracefullyDisconnect_TheCurrentCircuit()
129129
await Task.WhenAny(Task.Delay(10000), GracefulDisconnectCompletionSource.Task);
130130

131131
// Assert
132-
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages);
133-
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages);
132+
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitTerminatedGracefully"), Messages.ToArray());
133+
Assert.DoesNotContain((Extensions.Logging.LogLevel.Debug, "CircuitDisconnectedPermanently"), Messages.ToArray());
134134
}
135135

136136
private void Log(WriteContext wc)

src/Components/test/E2ETest/Tests/ComponentRenderingTestBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ public void CanFocusDuringOnAfterRenderAsyncWithFocusInEvent(string triggerButto
485485
Browser.Equal("focus-input-onafterrender", () => Browser.SwitchTo().ActiveElement().GetAttribute("id"));
486486

487487
// As well as actually focusing and triggering the onfocusin event, we should not be seeing any errors
488-
var log = Browser.Manage().Logs.GetLog(LogType.Browser);
488+
var log = Browser.Manage().Logs.GetLog(LogType.Browser).ToArray();
489489
Assert.DoesNotContain(log, entry => entry.Level == LogLevel.Severe);
490490
}
491491

src/Components/test/E2ETest/Tests/FormsTest.cs

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public void InputDateInteractsWithEditContext_NonNullableDateTime()
212212
Browser.Equal("modified valid", () => renewalDateInput.GetAttribute("class"));
213213

214214
// Can become invalid
215-
ApplyInvalidInputDateValue(".renewal-date input", "11111-11-11");
215+
renewalDateInput.SendKeys("11-11-11111\t");
216216
Browser.Equal("modified invalid", () => renewalDateInput.GetAttribute("class"));
217217
Browser.Equal(new[] { "The RenewalDate field must be a date." }, messagesAccessor);
218218

@@ -236,11 +236,11 @@ public void InputDateInteractsWithEditContext_NullableDateTimeOffset()
236236

237237
// Validates on edit
238238
Browser.Equal("valid", () => expiryDateInput.GetAttribute("class"));
239-
expiryDateInput.SendKeys("01/01/2000\t");
239+
expiryDateInput.SendKeys("01-01-2000\t");
240240
Browser.Equal("modified valid", () => expiryDateInput.GetAttribute("class"));
241241

242242
// Can become invalid
243-
ApplyInvalidInputDateValue(".expiry-date input", "11111-11-11");
243+
expiryDateInput.SendKeys("11-11-11111\t");
244244
Browser.Equal("modified invalid", () => expiryDateInput.GetAttribute("class"));
245245
Browser.Equal(new[] { "The OptionalExpiryDate field must be a date." }, messagesAccessor);
246246

@@ -264,21 +264,14 @@ public void InputDateInteractsWithEditContext_TimeInput()
264264
Browser.Equal("modified valid", () => departureTimeInput.GetAttribute("class"));
265265

266266
// Can become invalid
267-
ApplyInvalidInputDateValue(".departure-time input", "01:234:56");
267+
// Stricly speaking the following is equivalent to the empty state, because that's how incomplete input is represented
268+
// We don't know of any way to produce a different (non-empty-equivalent) state using UI gestures, so there's nothing else to test
269+
departureTimeInput.SendKeys($"20{Keys.Backspace}\t");
268270
Browser.Equal("modified invalid", () => departureTimeInput.GetAttribute("class"));
269271
Browser.Equal(new[] { "The DepartureTime field must be a time." }, messagesAccessor);
270-
271-
// Empty is invalid, because it's not nullable
272-
departureTimeInput.SendKeys($"{Keys.Backspace}\t{Keys.Backspace}\t{Keys.Backspace}\t");
273-
Browser.Equal("modified invalid", () => departureTimeInput.GetAttribute("class"));
274-
Browser.Equal(new[] { "The DepartureTime field must be a time." }, messagesAccessor);
275-
276-
departureTimeInput.SendKeys("07201\t");
277-
Browser.Equal("modified valid", () => departureTimeInput.GetAttribute("class"));
278-
Browser.Empty(messagesAccessor);
279272
}
280273

281-
[Fact]
274+
[Fact(Skip = "https://github.com/dotnet/aspnetcore/issues/35498")]
282275
public void InputDateInteractsWithEditContext_MonthInput()
283276
{
284277
var appElement = MountTypicalValidationComponent();
@@ -287,11 +280,11 @@ public void InputDateInteractsWithEditContext_MonthInput()
287280

288281
// Validates on edit
289282
Browser.Equal("valid", () => visitMonthInput.GetAttribute("class"));
290-
visitMonthInput.SendKeys("03\t2005\t");
283+
visitMonthInput.SendKeys($"03{Keys.ArrowRight}2005\t");
291284
Browser.Equal("modified valid", () => visitMonthInput.GetAttribute("class"));
292285

293286
// Can become invalid
294-
ApplyInvalidInputDateValue(".visit-month input", "05/1992");
287+
visitMonthInput.SendKeys($"11{Keys.ArrowRight}11111\t");
295288
Browser.Equal("modified invalid", () => visitMonthInput.GetAttribute("class"));
296289
Browser.Equal(new[] { "The VisitMonth field must be a year and month." }, messagesAccessor);
297290

@@ -300,12 +293,13 @@ public void InputDateInteractsWithEditContext_MonthInput()
300293
Browser.Equal("modified invalid", () => visitMonthInput.GetAttribute("class"));
301294
Browser.Equal(new[] { "The VisitMonth field must be a year and month." }, messagesAccessor);
302295

303-
visitMonthInput.SendKeys("05\t2007\t");
296+
visitMonthInput.Clear();
297+
visitMonthInput.SendKeys($"05{Keys.ArrowRight}2007\t");
304298
Browser.Equal("modified valid", () => visitMonthInput.GetAttribute("class"));
305299
Browser.Empty(messagesAccessor);
306300
}
307301

308-
[Fact]
302+
[Fact(Skip = "https://github.com/dotnet/aspnetcore/issues/35498")]
309303
[QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/34884")]
310304
public void InputDateInteractsWithEditContext_DateTimeLocalInput()
311305
{
@@ -319,7 +313,7 @@ public void InputDateInteractsWithEditContext_DateTimeLocalInput()
319313
Browser.Equal("modified valid", () => appointmentInput.GetAttribute("class"));
320314

321315
// Can become invalid
322-
ApplyInvalidInputDateValue(".appointment-date-time input", "1234/567/89 33:44 FM");
316+
appointmentInput.SendKeys($"11{Keys.ArrowRight}11{Keys.ArrowRight}11111{Keys.ArrowRight}\t");
323317
Browser.Equal("modified invalid", () => appointmentInput.GetAttribute("class"));
324318
Browser.Equal(new[] { "The AppointmentDateAndTime field must be a date and time." }, messagesAccessor);
325319

@@ -862,21 +856,6 @@ private Func<string[]> CreateValidationMessagesAccessor(IWebElement appElement)
862856
.ToArray();
863857
}
864858

865-
private void ApplyInvalidInputDateValue(string cssSelector, string invalidValue)
866-
{
867-
// It's very difficult to enter an invalid value into an <input type=date>, because
868-
// most combinations of keystrokes get normalized to something valid. Additionally,
869-
// using Selenium's SendKeys interacts unpredictably with this normalization logic,
870-
// most likely based on timings. As a workaround, use JS to apply the values. This
871-
// should only be used when strictly necessary, as it doesn't represent actual user
872-
// interaction as authentically as SendKeys in other cases.
873-
var javascript = (IJavaScriptExecutor)Browser;
874-
javascript.ExecuteScript(
875-
$"document.querySelector('{cssSelector}').value = {JsonSerializer.Serialize(invalidValue, TestJsonSerializerOptionsProvider.Options)}");
876-
javascript.ExecuteScript(
877-
$"document.querySelector('{cssSelector}').dispatchEvent(new KeyboardEvent('change'))");
878-
}
879-
880859
private void EnsureAttributeRendering(IWebElement element, string attributeName, bool shouldBeRendered = true)
881860
{
882861
Browser.Equal(shouldBeRendered, () => element.GetAttribute(attributeName) != null);

src/Components/test/testassets/BasicTestApp/ElementFocusComponent.razor

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,18 @@
3030
{
3131
Task.Run(async () =>
3232
{
33-
await Task.Yield();
34-
performFocusDuringOnAfterRender = true;
35-
_ = InvokeAsync(StateHasChanged);
33+
await Task.Delay(500);
34+
_ = InvokeAsync(() =>
35+
{
36+
performFocusDuringOnAfterRender = true;
37+
StateHasChanged();
38+
});
3639
});
3740
}
3841

3942
private async Task FocusDuringOnAfterRenderViaAwait()
4043
{
41-
await Task.Yield();
44+
await Task.Delay(500);
4245
performFocusDuringOnAfterRender = true;
4346
}
4447

0 commit comments

Comments
 (0)