How to press and hold non-modifier key (space key)

2020-06-21 07:43发布

问题:

I met a problem, that selenium cannot press and hold key that is not in this list -

Keys.SHIFT, 
Keys.CONTROL, 
Keys.ALT, 
Keys.META,
Keys.COMMAND, 
Keys.LEFT_ALT, 
Keys.LEFT_CONTROL,
Keys.LEFT_SHIFT

My application shows instructions only when space key is pressed and hold. I want to write browser tests for this.

I am using ProtractorJS, but it seems like general limitation for such action, everywhere in selenium when you try to use keyDown for other key - you will get an exception with message like this - "Key Down / Up events only make sense for modifier keys."

here is link to Selenium Java code: https://github.com/SeleniumHQ/selenium/blob/master/java/client/src/org/openqa/selenium/interactions/internal/SingleKeyAction.java#L48

And same check in selenium js code: https://github.com/SeleniumHQ/selenium/blob/master/javascript/webdriver/actionsequence.js#L301

How i can press and hold non-modifier key? Space key in my case.

UPDATE: Thanks to Florent B. answer. After little modifying - works perfectly for me. Had to add switching to frame, and dispatching event to document instead specific element for my case.

browser.switchTo().frame('workspace');  
const SIMULATE_KEY =  
"var e = new Event('keydown');" +  
"e.keyCode = 32;" +  //spacebar keycode
"e.which = e.keyCode;" +  
"e.altKey = false;" +  
"e.ctrlKey = false;" +  
"e.shiftKey = false;" +  
"e.metaKey = false;" +  
"e.bubbles = true;" +  
"document.dispatchEvent(e);";  
browser.executeScript(SIMULATE_KEY);

回答1:

The Selenium API doesn't provide this feature. From the official documentation:

https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol

The server must process the key sequence as follows: Each key that appears on the keyboard without requiring modifiers are sent as a keydown followed by a key up.

However you could simulate the key event with a piece of Javascript:

const SIMULATE_KEY =
  "var e = new Event(arguments[0]);" +
  "e.key = arguments[1];" +
  "e.keyCode = e.key.charCodeAt(0);" +
  "e.which = e.keyCode;" +
  "e.altKey = false;" +
  "e.ctrlKey = false;" +
  "e.shiftKey = false;" +
  "e.metaKey = false;" +
  "e.bubbles = true;" +
  "arguments[2].dispatchEvent(e);";

var target = driver.findElement(By.Id("..."));

// press the key "a"
browser.executeScript(SIMULATE_KEY, "keydown", "a", target);

// release the key "a"
browser.executeScript(SIMULATE_KEY, "keyup", "a", target);


回答2:

If you can't find an answer using selenium you could trigger a script with another tool (such as AutoIt or AutoHotKey) just to do the key press and hold.

It's a pain in the ass but it may be your only option.