Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,45 @@ internal static void HideKeyboard(IApp app, AppiumDriver? driver, bool isEditor)
app.DismissKeyboard();
}

// Polls for a keyboard-related element using the non-throwing FindElements API instead of a
// bare FindElement. On iOS the soft keyboard (and its buttons) can still be animating in when
// the lookup runs, so a bare FindElement throws NoSuchElementException intermittently. Returns
// null if the element never appears within the timeout so callers can react deterministically.
// See dotnet/maui#36396 and dotnet/maui#36393.
static AppiumElement? WaitForKeyboardElement(AppiumDriver? driver, OpenQA.Selenium.By locator, TimeSpan? timeout = null)
{
if (driver is null)
return null;

timeout ??= TimeSpan.FromSeconds(5);
var start = DateTime.Now;
while (true)
{
var elements = driver.FindElements(locator);
if (elements.Count > 0)
return elements[0];

if (DateTime.Now - start >= timeout.Value)
return null;

System.Threading.Thread.Sleep(200);
}
}

internal static System.Drawing.Point? FindiOSKeyboardLocation(AppiumDriver? driver)
{
if (driver?.IsKeyboardShown() == true)
{
var keyboard = driver.FindElement(MobileBy.ClassName("UIAKeyboard"));
return keyboard.Location;
var keyboard = WaitForKeyboardElement(driver, MobileBy.ClassName("UIAKeyboard"));
return keyboard?.Location;
}
return null;
}

internal static void CloseiOSEditorKeyboard(IApp app, AppiumDriver? driver)
{
var doneButtonName = app is AppiumIOSApp iosApp && HelperExtensions.IsIOS26OrHigher(iosApp) ? "selected" : "Done";
var keyboardDoneButton = driver?.FindElement(MobileBy.Name(doneButtonName));
var keyboardDoneButton = WaitForKeyboardElement(driver, MobileBy.Name(doneButtonName));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[major] UI Test ReliabilityWaitForKeyboardElement can now time out and return null, but CloseiOSEditorKeyboard still treats the Done/selected key as optional via the following null-conditional click. If the accessory button never appears, the helper silently leaves the keyboard open and the test either fails later in an unrelated place or can continue with the wrong state. Please assert/fail when this required keyboard button is missing (for example ClassicAssert.NotNull(keyboardDoneButton, ...)) before clicking it.

keyboardDoneButton?.Click();
}

Expand All @@ -148,7 +173,7 @@ internal static void EntryNextEditorScrollingTest(IApp app, string galleryName)
// Unintentionally types a 'V' but also presses the next keyboard key
internal static void NextiOSKeyboardPress(AppiumDriver? driver)
{
var keyboard = driver?.FindElement(MobileBy.ClassName("UIAKeyboard"));
var keyboard = WaitForKeyboardElement(driver, MobileBy.ClassName("UIAKeyboard"));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[major] UI Test Reliability — This lookup now returns null on timeout, but NextiOSKeyboardPress still makes the required Next action optional via keyboard?.SendKeys on the next line. In EntryNextEditorScrollingTest, failing to press Next can leave focus on the previous field while later visibility checks keep running, which hides the real keyboard failure. Please fail immediately when the keyboard is not found before sending the newline.

keyboard?.SendKeys("\n");
}

Expand Down
Loading