Skip to content
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

bug: Appium 2 send_keys('0.25') to a web view number field loses characters up to decimal #18765

Open
1 task done
jpangburn opened this issue Jun 14, 2023 · 24 comments
Open
1 task done
Labels
Mobile Safari related to mobile Safari driver ThirdParty upstream problems

Comments

@jpangburn
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Using Appium 2.0 against a Cordova iOS app on a real iPad device with a python appium client with driver in webview mode, when I do:

element.send_keys('0.25')

If that element is an input of type number, then the field will contain '25' with the '0.' having been truncated. But if that element is a plain text input field, then it will contain the expected '0.25' characters. In the number field I can type in '0.25' manually and it works fine.

I can also workaround by doing something like:

driver.execute_script('document.querySelector("#your-input-id").value = "0.25";')

In that case the number field has the full decimal value rather than just '25'.

Expected Behavior

I've had this code for years and it worked fine in Appium 1.X without truncating that value in number fields. I expected it would still be working in 2.0.

Minimal Reproducible Example

I'm not sure how to provide a Cordova test app with all the ancillary parts to reproduce.

Environment

  • Operating system: Mac Ventura 13.4
  • If running via appium CLI...
    • Appium CLI version (output of appium --version): 2.0.0-beta.71
    • Node.js version (output of node --version): v20.3.0
    • npm version (output of npm --version): 9.6.7
    • Last appium version which did not exhibit the problem: 1.X
  • If running Appium Desktop, its version: N/A
  • Appium driver(s) and their version(s): xcuitest@4.32.0
  • Appium plugin(s) and their version(s): N/A
  • Platform and version under test: iPadOS 16.5
  • Real device or emulator/simulator: real device (iPad Mini 5)

Link to Appium Logs

No response

Futher Information

Here's the top and bottom of my appium log in case it helps. You can see it tries to send my intended decimal value "0.25","value":["0",".","2","5"],"id":". The full log file is attached here as well, but there is a lot of other fields that get filled out by my automation test before it gets to the problem field where I stopped it.

% appium server --base-path=/wd/hub
[Appium] Welcome to Appium v2.0.0-beta.71 (REV 552db40622bb7a82d9c6d67d2d6bcf3694b47e30)
[Appium] Non-default server args:
[Appium] {
[Appium] basePath: '/wd/hub'
[Appium] }
[Appium] Attempting to load driver xcuitest...
[debug] [Appium] Requiring driver at /Users/jpangburn/.appium/node_modules/appium-xcuitest-driver
[Appium] Appium REST http interface listener started on 0.0.0.0:4723/wd/hub
[Appium] Available drivers:
[Appium] - xcuitest@4.32.0 (automationName 'XCUITest')
[Appium] No plugins have been installed. Use the "appium plugin" command to install the one(s) you want to use.

...

�[38;5;0m[HTTP]�[0m �[37m<-- POST /wd/hub/session/4698ead6-d7d9-4b72-8cf7-0b77e0abb7c0/element/:wdc:1686713894234/element �[39m�[32m200�[39m �[90m46 ms - 101�[39m
�[38;5;0m[HTTP]�[0m �[90m�[39m
�[38;5;0m[HTTP]�[0m �[37m-->�[39m �[37mPOST�[39m �[37m/wd/hub/session/4698ead6-d7d9-4b72-8cf7-0b77e0abb7c0/element/:wdc:1686713894252/value�[39m
�[38;5;0m[HTTP]�[0m �[90m{"text":"0.25","value":["0",".","2","5"],"id":":wdc:1686713894252"}�[39m
[debug] �[38;5;32m[XCUITestDriver@6f1d (4698ead6)]�[0m Calling AppiumDriver.setValue() with args: [["0",".","2","5"],":wdc:1686713894252","4698ead6-d7d9-4b72-8cf7-0b77e0abb7c0"]
[debug] �[38;5;32m[XCUITestDriver@6f1d (4698ead6)]�[0m Executing command 'setValue'
[debug] �[38;5;128m[RemoteDebugger]�[0m Executing atom 'click' with 'args=[{"ELEMENT":":wdc:1686713894252"}]; frames='
[debug] �[38;5;128m[RemoteDebugger]�[0m Executing 'click' atom in default context
[debug] �[38;5;128m[RemoteDebugger]�[0m Sending javascript command: '(function(){return function(){var h,aa=this;fun...'
[debug] �[38;5;128m[RemoteDebugger]�[0m Sending '_rpc_forwardSocketData:' message to app 'PID:1609', page '2', target 'page-15' (id: 832): 'Runtime.evaluate'
[debug] �[38;5;128m[RemoteDebugger]�[0m Received data response from send (id: 832): '"{"status":0,"value":null}"'
[debug] �[38;5;128m[RemoteDebugger]�[0m Sending to Web Inspector took 50ms
[debug] �[38;5;128m[RemoteDebugger]�[0m Received result for atom 'click' execution: null
[debug] �[38;5;128m[RemoteDebugger]�[0m Executing atom 'type' with 'args=[{"ELEMENT":":wdc:1686713894252"},["0",".","2","5"]]; frames='
[debug] �[38;5;128m[RemoteDebugger]�[0m Executing 'type' atom in default context
[debug] �[38;5;128m[RemoteDebugger]�[0m Sending javascript command: '(function(){return function(){var h,aa=this;fun...'
[debug] �[38;5;128m[RemoteDebugger]�[0m Sending '_rpc_forwardSocketData:' message to app 'PID:1609', page '2', target 'page-15' (id: 834): 'Runtime.evaluate'
[debug] �[38;5;128m[RemoteDebugger]�[0m Received data response from send (id: 834): '"{"status":0,"value":null}"'
[debug] �[38;5;128m[RemoteDebugger]�[0m Sending to Web Inspector took 31ms
[debug] �[38;5;128m[RemoteDebugger]�[0m Received result for atom 'type' execution: null

appium_log.txt

@jpangburn jpangburn added Bug a problem that needs fixing Needs Triage bugs which are not yet confirmed labels Jun 14, 2023
@mykola-mokhnach mykola-mokhnach added Mobile Safari related to mobile Safari driver Needs Triage bugs which are not yet confirmed and removed Needs Triage bugs which are not yet confirmed Bug a problem that needs fixing labels Jun 14, 2023
@KazuCocoa
Copy link
Member

Do you have an example app i could try or have a web page?

Maybe it is something in the remote debugger, which is the same as WebView/Safari. Then, I tried to send 0.25 to a google's search field as below as a similar situation. It was xcuitest@4.31.0 with iPadOS 17 though.

Screen Shot 2023-06-14 at 12 26 20 AM

[HTTP] --> POST /session/91aecd9d-30bc-42d3-84aa-25ac9fc19df7/element/:wdc:1686727545031/value
[HTTP] {"value":["0",".","2","5"],"text":"0.25"}
[debug] [XCUITestDriver@3c9f (91aecd9d)] Calling AppiumDriver.setValue() with args: [["0",".","2","5"],":wdc:1686727545031","91aecd9d-30bc-42d3-84aa-25ac9fc19df7"]
[debug] [XCUITestDriver@3c9f (91aecd9d)] Executing command 'setValue'
[debug] [RemoteDebugger] Executing atom 'click' with 'args=[{"ELEMENT":":wdc:1686727545031"}]; frames='
[debug] [RemoteDebugger] Executing 'click' atom in default context
[debug] [RemoteDebugger] Sending javascript command: '(function(){return function(){var h,aa=this;fun...'
[debug] [RemoteDebugger] Sending '_rpc_forwardSocketData:' message to app 'PID:21450', page '1', target 'page-45' (id: 48): 'Runtime.evaluate'
[debug] [RemoteDebugger] Received data response from send (id: 48): '"{\"status\":0,\"value\":null}"'
[debug] [RemoteDebugger] Sending to Web Inspector took 293ms
[debug] [RemoteDebugger] Received result for atom 'click' execution: null
[debug] [RemoteDebugger] Executing atom 'type' with 'args=[{"ELEMENT":":wdc:1686727545031"},["0",".","2","5"]]; frames='
[debug] [RemoteDebugger] Executing 'type' atom in default context
[debug] [RemoteDebugger] Sending javascript command: '(function(){return function(){var h,aa=this;fun...'
[debug] [RemoteDebugger] Sending '_rpc_forwardSocketData:' message to app 'PID:21450', page '1', target 'page-45' (id: 50): 'Runtime.evaluate'
[debug] [RemoteDebugger] Received data response from send (id: 50): '"{\"status\":0,\"value\":null}"'
[debug] [RemoteDebugger] Sending to Web Inspector took 220ms
[debug] [RemoteDebugger] Received result for atom 'type' execution: null
[debug] [XCUITestDriver@3c9f (91aecd9d)] Responding to client with driver.setValue() result: null
[HTTP] <-- POST /session/91aecd9d-30bc-42d3-84aa-25ac9fc19df7/element/:wdc:1686727545031/value 200 567 ms - 14

@KazuCocoa KazuCocoa added Needs Info typically non-actionable; needs author to respond and removed Needs Triage bugs which are not yet confirmed labels Jun 14, 2023
@jpangburn
Copy link
Author

Hey @KazuCocoa , thanks for the suggestion! For me, it seems to work fine on text fields, it's the <input type="number" fields that have the problem. I didn't know you could directly control mobile Safari from Appium- I thought you needed debug builds of your own software to use XCUITest. I'll look into this.

For anyone else that runs into this before there's a solution, I worked around it in my testing framework with this ugly little function in my utils library (which labels the driver as _driver):

def hack_number_input(querySelector, value):
    script_content = '''
var element = document.querySelector("%s");
element.value = "%s";
element.dispatchEvent(new Event('input', { 'bubbles': true }));
''' %(querySelector, value,)
    _driver.execute_script(script_content)

Since I only have 5-7 places where I needed a decimal number input, I just changed those places to call this. You call it like this utils.hack_number_input("[name='cloudCoverPercentage']", "0.25") for an input like <input type="number" name="cloudCoverPercentage".... The name is obviously so I remember to get rid of it when this bug is resolved at some point.

@mykola-mokhnach
Copy link
Collaborator

mykola-mokhnach commented Jun 14, 2023

I believe this logic lives in selenium atoms, which is a third party component for us...

Perhaps, you might have better luck if Safari driver is used instead

@jlipps
Copy link
Member

jlipps commented Jun 14, 2023

Seems like the atoms are not working super well anymore (probably unrelated but similar weirdness with #17415 as well)

@jpangburn
Copy link
Author

Following @KazuCocoa suggestion, I made a super simple test page and used Appium to open it from an iPad's Safari. It has the same problem in both a real device running iPadOS 16.5 and a simulator running 16.4.

Here's the code:

from appium import webdriver
from selenium.webdriver.common.by import By
import os

desired_caps_sim = {
    "platformName": "iOS",
    "platformVersion": "16.4",
    "deviceName": "iPad mini (6th generation)",
    "automationName": "XCUITest",
    "browserName": "Safari",
}

desired_caps_ipadmini = {
    "platformName": "iOS",
    "platformVersion": "16.4",
    "deviceName": "iPad",
    "udid": "###########", #change this to your device udid
    "automationName": "XCUITest",
    "browserName": "Safari",
}

driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps_sim)

driver.get("https://jpangburn.github.io/inputnumber/")
driver.switch_to.context(driver.contexts[-1])
element = driver.find_element(By.ID, "testfield")
element.clear()
element.send_keys('0.25')

# save a screenshot
directory = '%s/' % os.getcwd()
file_name = 'screenshot.png'
driver.save_screenshot(directory + file_name)

Forgive me if the code is verbose, I just learned you can even do this :-)

Here is the real device screenshot (you can see the first two characters are truncated)
screenshot_device

Here is the simulator screenshot
screenshot_simulator

@mykola-mokhnach I haven't tried the Safari driver because I'm using it for testing a hybrid mobile app so as I understand it, and please correct me if I'm wrong, I need to use the XCUITest driver for that.

@jlipps
Copy link
Member

jlipps commented Jun 15, 2023

@jpangburn what if you split the send_keys into one separate call for each character? does that change it at all?

@mykola-mokhnach mykola-mokhnach added ThirdParty upstream problems and removed Needs Info typically non-actionable; needs author to respond labels Jun 15, 2023
@jpangburn
Copy link
Author

@jlipps That's a good question, the period character acts just like the .clear() method. I updated the code to add another character before the period to differentiate from backspace:

element.send_keys('5')
element.send_keys('6')
element.send_keys('.')
element.send_keys('2')
element.send_keys('5')

Here's a video stepping through that. You can see it puts "56" in the field, clears it, then puts "25":

screen_record.mov

@jlipps
Copy link
Member

jlipps commented Jun 16, 2023

mind boggling. what if you send the unicode for a period instead? \002E

@jpangburn
Copy link
Author

@jlipps yeah, it's bizarre. If you type it in manually it works just fine, but through appium it's the same as a .clear() call. The unicode period is a clever idea, but it has the same result.

@jlipps
Copy link
Member

jlipps commented Jun 16, 2023

ok. something is broken with the atoms then, and it's an open task to build the new ones. unfortunately it's not straightforward. the only other workaround i can think of is executing javascript instead. something like driver.execute_script("arguments[0].innerHTML='0.25'", element) (double check python syntax tho)

@jpangburn
Copy link
Author

@jlipps Thanks for looking into this. I did provide a workaround above for others who came here with the same problem: #18765 (comment)

The workaround fires the input event so forms will get validated, etc.

@jlipps
Copy link
Member

jlipps commented Jun 16, 2023

ah, missed that before. thanks.

@mykola-mokhnach
Copy link
Collaborator

@jlipps shall we update/close this issue?

@jlipps
Copy link
Member

jlipps commented Aug 24, 2023

@jpangburn can you retry with the latest xcuitest driver? it has new selenium atoms and might have fixed the issue.

@jpangburn
Copy link
Author

@jlipps Sure. The version I was running before showed:
[Appium] Available drivers:
[Appium] - xcuitest@4.32.0 (automationName 'XCUITest')

In case I need to do more, I updated like this "appium driver update xcuitest". Now it says:
[Appium] Available drivers:
[Appium] - xcuitest@4.34.1 (automationName 'XCUITest')

Unfortunately the result is the same. It still shows "25" in the input field.

If you have a suggestion for me to update something else I'm happy to try it again.

@jlipps
Copy link
Member

jlipps commented Aug 25, 2023

@jpangburn from :

The default stepping value for number inputs is 1, allowing only integers to be entered—unless the stepping base is not an integer.

and

The number input type should only be used for incremental numbers, especially when spinbutton incrementing and decrementing are helpful to user experience.

Maybe the issue is that your field isn't correctly set up for decimal values? What if you add step="0.25" to it?

@jpangburn
Copy link
Author

@jlipps That only takes effect when you use the buttons. You can type in whatever value you want. Do you have Safari? The site's at https://jpangburn.github.io/inputnumber/. You can type in any number you want, then click on an empty part of the screen and it doesn't try to reject the number or anything. So using Appium should be the same, right? It's just typing the value in as you would do.

Also, this is a new bug. It didn't used to do this. Appium 1.X was putting "0.25" in the same fields with no problem. The workaround also lets you put "0.25" in the field, it's just the 2.X sendkeys that's having trouble.

@jpangburn
Copy link
Author

Sorry I forgot to mention, I did try it anyway and it didn't make any difference. I noticed the mobile Safari on iPadOS and iOS don't seem to have step buttons on number fields like MacOS Safari does. So doesn't seem to make any difference to the mobile UI if you have step="0.25" in there or not, nor did it make any difference on this sendkeys problem with Appium.

@jlipps
Copy link
Member

jlipps commented Aug 28, 2023

Hmm OK I'll investigate some more. I'm surprised that it worked in Appium 1.x. There haven't been any remote debugger updates in the last 3 years except for the most recent one. So if there was a regression in one of the new xcuitest driver updates it implies that the issue is not actually in the atoms like we thought. Just to double check: are you sure you're comparing apples to apples in terms of iOS and xcode versions when checking Appium 1 vs 2?

@jpangburn
Copy link
Author

@jlipps No, it's not an apples to apples comparison. I had to update Xcode to work with newer iOS when I was releasing a new version of my software, and I forget what it was, but something was broken after that update in my test framework with Appium 1.X. After looking around I found that Appium 2.X resolved whatever issue had been introduced. So the iOS, Xcode, and Appium versions all were updated.

That said, this code was introduced on this project 8 years ago and has worked through all those previous iOS and Xcode and Appium updates over the years. But when I went to Appium 2.X it stopped working.

Still, regardless of whatever versions worked in the past... shouldn't you be able to call send_keys and have it work just like if the user typed those keys on their keyboard? Or am I misunderstanding the point of the send_keys method? When I'm in the browser and type "0.25" it doesn't clear the field when I type the period and "0.25" shows up in the field just fine- so the question really is why is this not happening with send_keys right now in current versions of Xcode, iOS, and Appium? Suppose a user comes along today out of the blue and tries to do this, shouldn't it work?

@jlipps
Copy link
Member

jlipps commented Aug 28, 2023

Yes, it should work. However specifically for mobile web on safari we're in a bit of a duct tape and chicken wire situation. There is no official webdriver implementation that works for webviews, so the fact that send_keys "should" behave the same way as a user typing is sort of immaterial. It all boils down to what's possible with sending JavaScript snippets across the remote debug protocol. Currently we're using a combination of two such snippets (called atoms or fragments in the webdriver world): click and type. The code for these snippets did not change in the time window of your regression.

My current best guess is that something about the iOS update broke this on Apple's side, since I don't think anything material changed on the Appium side.

But yes, it should work, which is why I am continuing to investigate it. I can think of a few workarounds to try (including enshrining your workaround as an actual option in the driver, toggled by a capability or a setting).

@jpangburn
Copy link
Author

Hehe good description- duct tape and chicken wire. We've all been there.

My workaround worked well for my use case, which was to have the value show up in the field and have events triggered with the final value for validation. I just added a method in my utils file "numeric_input_hack" or something like that with a locator and what you wanted to send it. Not as nice as calling send_keys but functionally equivalent for my use case. I don't know what other use cases people would have that would break with that though, probably stuff that works as you type I suppose.

Wish I hadn't deleted my Appium 1.x install. I'm curious if it works on this simple case.

@jpangburn
Copy link
Author

jpangburn commented Aug 28, 2023

@jlipps Curiosity won. I had an old iPhone laying around with 15.7 still on it, so installed Appium Desktop which runs appium 1.22.3. Of course I had to replace the WebDriverAgent in there with the latest one from Appium 2 so that it would build on my Mac M1, but otherwise it's stock. I added a new capabilities entry to that same code I provided above to connect to that iPhone.

It worked like a charm. In the automated Safari the number field came up "0.25".

I tried using that old version of Appium to drive my 16.4 simulator, and it installs the webdriveragent and starts Safari but gets stuck on the page that says "Let's browse!" and complains "Mobile Safari cannot open 'http://0.0.0.0:4723/welcome' after 25.564s. Its process com.apple.mobilesafari does not exist in the list of Simulator processes". But I can inspect that simulated mobile Safari from the mac's web inspector. So I imagine it's some incompatibility between the old appium and a relatively new iOS version?

Still, it worked on a real device in iOS 15.7.

@jlipps
Copy link
Member

jlipps commented Sep 1, 2023

Yep ok. I'll keep looking into this as I have time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Mobile Safari related to mobile Safari driver ThirdParty upstream problems
Projects
None yet
Development

No branches or pull requests

4 participants