|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | 3 |
|
4 | 4 | using System.Globalization; |
| 5 | +using System.Linq; |
5 | 6 | using BasicTestApp; |
6 | 7 | using Microsoft.AspNetCore.Components.E2ETest.Infrastructure; |
7 | 8 | using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; |
@@ -426,16 +427,79 @@ public void CanRefreshItemsProviderResultsInPlace() |
426 | 427 | name => Assert.Equal("Person 3", name)); |
427 | 428 | } |
428 | 429 |
|
429 | | - [Fact] |
430 | | - public void CanScrollWhenAppliedScale() |
| 430 | + [Theory] |
| 431 | + [InlineData("1")] |
| 432 | + [InlineData("2")] |
| 433 | + [InlineData("0.5")] |
| 434 | + public void CanScrollWhenAppliedScale(string scaleY) |
431 | 435 | { |
432 | 436 | Browser.MountTestComponent<VirtualizationScale>(); |
433 | 437 | var container = Browser.Exists(By.Id("virtualize")); |
434 | 438 |
|
435 | | - var people = GetPeopleNames(container); |
436 | | - Assert.True(GetPeopleNames(container).Length > 0); |
437 | | - ScrollTopToEnd(Browser, container); |
438 | | - Assert.True(GetPeopleNames(container).Length > 0); |
| 439 | + Browser.True(() => |
| 440 | + { |
| 441 | + try |
| 442 | + { |
| 443 | + return Browser.FindElement(By.Id("virtualize")) |
| 444 | + .FindElements(By.CssSelector("tbody tr.person")).Count > 0; |
| 445 | + } |
| 446 | + catch (StaleElementReferenceException) |
| 447 | + { |
| 448 | + return false; |
| 449 | + } |
| 450 | + }); |
| 451 | + |
| 452 | + Browser.FindElement(By.Id("scale-y-input")).Clear(); |
| 453 | + Browser.FindElement(By.Id("scale-y-input")).SendKeys(scaleY); |
| 454 | + Browser.FindElement(By.Id("btn")).Click(); |
| 455 | + |
| 456 | + // Scroll slowly (10px increments) and check if the first visible item changes unexpectedly. |
| 457 | + // If the item index goes backward (e.g., from "5" to "4") instead of |
| 458 | + // staying the same or advancing, that indicates flashing. |
| 459 | + const string detectFlashingScript = @" |
| 460 | + var done = arguments[0]; |
| 461 | + (async () => { |
| 462 | + const SCROLL_INCREMENT = 10; |
| 463 | + let previousTopItemIndex = null; |
| 464 | + const container = document.querySelector('#virtualize'); |
| 465 | + if (!container) { |
| 466 | + done(false); |
| 467 | + return; |
| 468 | + } |
| 469 | + |
| 470 | + const getTopVisibleItemIndex = () => { |
| 471 | + const firstRow = container.querySelector('tbody tr.person span'); |
| 472 | + if (!firstRow) return null; |
| 473 | + return parseInt(firstRow.textContent, 10); |
| 474 | + }; |
| 475 | + |
| 476 | + while (true) { |
| 477 | + const previousScrollTop = container.scrollTop; |
| 478 | + container.scrollTop += SCROLL_INCREMENT; |
| 479 | + await new Promise(resolve => requestAnimationFrame(resolve)); |
| 480 | + const currentScrollTop = container.scrollTop; |
| 481 | + if (currentScrollTop === previousScrollTop) { |
| 482 | + done(true); |
| 483 | + return; |
| 484 | + } |
| 485 | + const currentTopItemIndex = getTopVisibleItemIndex(); |
| 486 | + if (currentTopItemIndex === null) { |
| 487 | + done(false); |
| 488 | + return; |
| 489 | + } |
| 490 | + if (previousTopItemIndex !== null) { |
| 491 | + if (currentTopItemIndex < previousTopItemIndex) { |
| 492 | + done(false); |
| 493 | + return; |
| 494 | + } |
| 495 | + } |
| 496 | + previousTopItemIndex = currentTopItemIndex; |
| 497 | + } |
| 498 | + })();"; |
| 499 | + |
| 500 | + var jsExecutor = (IJavaScriptExecutor)Browser; |
| 501 | + var noFlashingDetected = (bool)jsExecutor.ExecuteAsyncScript(detectFlashingScript); |
| 502 | + Assert.True(noFlashingDetected); |
439 | 503 | } |
440 | 504 |
|
441 | 505 | [Theory] |
|
0 commit comments