Leo Li
Leo Li

Reputation: 203

Is it possible use keyboard actions without using the "PyAutoGUI" library on jenkins?

I am using Robotframework to create test scripts for an application. This application requires many keyboard click/action combinations that are unavoidable. Right now I am using the PyAutoGui library to simulate these actions and they are working fine, but when I run them through a headless browser on Jenkins, those actions are not registered.

The error that I get is "PyAutoGUI fail-safe triggered from mouse moving to upper-left corner. To disable this fail-safe, set pyautogui.FAILSAFE to False." However, even after changing the Failsafe value to false, the keyboard action is still not captured.

The weird thing is that if someone is physically logged into the Jenkins box while the tests are running, the library works perfectly fine, but when running headless, the library breaks.

Is there another library I can possible use or a possible work around for this situation?

Thanks in advance!

Upvotes: 6

Views: 4044

Answers (4)

jozefow
jozefow

Reputation: 786

The reason for such behaviour is that when there is no user logged in (physically or via RDP), there is no active desktop (think about all GUI elements, profiles, etc.) We had such issues in our environment. Here is a working solution:

  1. create a job which will establish an RDP session on Windows VMs so there will be an active desktop. The job cannot end the RDP session. It needs to be run in background (usually no problem, as if somebody else logs in with the same user, the session will switch to the new user but the desktop will be active. )
  2. make sure that, whenever you run your test jobs on Win VMs, there is already an RDP opened. Schedule job 1 to be run before tests on Win VMs.

From the technical details of job 1, we have our WinVM nodes named with the WIN prefix, so to get all Windows nodes, we query Jenkins via the Jenkins API.
Once we have a list of WinVMs (IP or hostnames), we run the following command on the Linux node looping with all discovered WinVMs nodes.

Basic command for one node :

   BUILD_ID=dontKillMe vncserver -kill :100 || true
   BUILD_ID=dontKillMe rm -rf /tmp/.X11-unix/X100 || true 
   BUILD_ID=dontKillMe vncserver :100
   BUILD_ID=dontKillMe DISPLAY=localhost:100
   BUILD_ID=dontKillMe export DISPLAY
   yum install -y freerdp
   ## loop through WinVMs below:    
   nohup xfreerdp -g <resolution> -u <user> -p <pas> <IP/hostname>
   ## end of loop

The magic is with nohup, as it runs the RDP session in the background after the job has been finished.

This is Centos with vncserver and xfreerdp installed.

#edit

You can ask the admin to create a WinVM for running tests, separating Jenkins with dev/test environment. In such way you could the open an RDP session on the node from anywhere or from Jenkins itself. For stability and performance, it is considered as a good practice not to run anything on the master.

Upvotes: 2

Leo Li
Leo Li

Reputation: 203

I was able to figure out a solution/work-around for my problem. I came across this post on google groups about multiple key combinations in robotframework automation and it was able to help me find a viable solution. Instead of trying to use the pyautogui library, we can use sendKeys to build a custom keyword to combine multiple keyboard actions. This approach worked perfectly for me, the only drawback is that now I have to pass a selector to focus on every time I want to use my custom keyword, but for my application that was not a huge issue.

I took the code from this Discussion and made a few slight modifications:

def customPressKey(self, locator, keys):
    keys =  keys.split(' + ')
    i = 0
    named_keys = []
    named_key_sequence = []
    named_key_seq_as_string = ''
    unnamed = '' 
    for key in keys:
    try:
        named_key = getattr(Keys, keys[i])
        print "%s. named key is %s." % (i + 1, key)
        named_keys.append(keys[i])
        i = i + 1
        except:
            print "The rest '%s' is unnamed." % key
            unnamed = str(key).lower()
            i = i + 1
    print "NAMED KEY(s):", named_keys
    for key in named_keys:
        named_key_sequence.append('Keys.%s' % key)
        named_key_seq_as_string = ','.join(named_key_sequence)
    print "NAMED KEY SEQUENCE:", named_key_sequence
    print "NAMED KEY SEQUENCE as STRING:", named_key_seq_as_string
    print "element.send_keys() call should look like this:"
    print "element.send_keys(%s, '%s')" % (named_key_seq_as_string, unnamed)
    element = self.find_element(locator)
    if unnamed:
        exec("element.send_keys(%s, '%s')" % (named_key_seq_as_string, unnamed))
    else:
        exec("element.send_keys(%s)" % (named_key_seq_as_string))

Upvotes: 0

soyacz
soyacz

Reputation: 457

You can workaround this by installing VNC server and run jenkins slave within it. Then browser will start with gui and test will work.

Upvotes: 0

Tyler C.
Tyler C.

Reputation: 141

I have been automating a lot of web applications at work.

I too started with PyAutoGUI, and had similar problems that you are experiencing going from my laptop to our production server that was running the scripts.

The solution I found was Selenium Webdriver. If what you are testing has an ip address, this may be the solution. In my opinion it is actually easier than PyAutoGUI.

Upvotes: 1

Related Questions