I have found a lot of information on this topic, but none of them seem to work (anymore).
What I want to do is to simulate key(down/press/up) events in Chrome 59(I really don't care about other browser). Simulating the Event itself is not the problem, but the problem is that I have not found a solution that is backwards compatible and contains the charCode/keyCode values. If it were up to me, I would update the code of the other application to check for key/code, but unfortunately it is not up to me.
What I have tried so far:
var evt = new KeyboardEvent(type, {code: options.charCode, key: options.keyCode, keyCode: options.keyCode, charCode: options.keyCode, which: options.which});
element.dispatchEvent(evt);
According to https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent this should work and create an event with the keyCode/charCode/which set, but it does not work:
My code (I have tried with and without quotes and with characters instead of numbers):
new KeyboardEvent("keypress", {code: 123, key: 123, keyCode: 123, charCode: 123, which: 123});
Output:
KeyboardEvent {isTrusted: false, key: "123", code: "123", location: 0, ctrlKey: falseā¦}
altKey:false
bubbles:false
cancelBubble:false
cancelable:false
charCode:0
code:"123"
composed:false
ctrlKey:false
currentTarget:null
defaultPrevented:false
detail:0
eventPhase:0
isComposing:false
isTrusted:false
key:"123"
keyCode:0
location:0
metaKey:false
path:Array(0)
repeat:false
returnValue:true
shiftKey:false
sourceCapabilities:null
srcElement:null
target:null
timeStamp:2469092.6000000006
type:"keypress"
view:null
which:0
__proto__:KeyboardEvent
I then had a look at the specification and noticed that the keyCode/charCode/which property are not there any more, which leads me to believe that it has been removed from the standard and it should not work like this any more: https://w3c.github.io/uievents/#keyboardevent
As this is clearly not working, I started to look into the deprecated function initKeyboardEvent and tried this:
var evt = document.createEvent("KeyboardEvent");
//Chrome hack
Object.defineProperty(evt, 'keyCode', {
get : function(){
return this.keyCodeVal;
}
});
Object.defineProperty(evt, 'which', {
get : function(){
return this.keyCodeVal
}
});
Object.defineProperty(evt, 'charCode', {
get : function(){
return this.charCodeVal
}
});
//initKeyBoardEvent seems to have different parameters in chrome according to MDN KeyboardEvent(sorry, can't post more than 2 links), but that did not work either
evt.initKeyboardEvent("keypress",
true,//bubbles
true,//cancelable
window,
false,//ctrlKey,
false,//altKey,
false,//shiftKey,
false,//metaKey,
123,//keyCode,
123//charCode
);
evt.charCodeVal = 123;
evt.keyCodeVal = 123;
So this already seemed promising, but when i dispatched the event, this is the event that I can see in the handler:
KeyboardEvent
altKey:false
bubbles:true
cancelBubble:false
cancelable:true
charCode:0
code:""
composed:false
ctrlKey:false
currentTarget:input#iceform:username.iceInpTxt.bookLoginTextbox
defaultPrevented:false
detail:0
eventPhase:2
isTrusted:false
key:""
keyCode:0
location:0
metaKey:true
path:Array[16]
repeat:false
returnValue:true
shiftKey:true
sourceCapabilities:null
srcElement:input#iceform:username.iceInpTxt.bookLoginTextbox
target:input#iceform:username.iceInpTxt.bookLoginTextbox
timeStamp:9932.905000000002
type:"keypress"
view:Window
which:0
__proto__:KeyboardEvent
This is when I finally gave up and decided to ask for help. Is there any way I can properly simulate those events in a way that it is also backwards compatible?
PLEASE DO NOT SUGGEST JQUERY OR SIMILIAR THINGS
OK i finally figured out the problem. The code itself is actually OK(the one with the deprecated initKeyboardEvent).
The problem is, that i was executing this in a contentscript of a chrome extension. In this case all the properties of the event get reset to their default values and THEN the event is raised. I am now adding a script to the page that contains exactly the same code and it works just fine.
Related
I am using a plugin that allows me to display an ad in video-js.
https://github.com/dirkjanm/videojs-preroll/blob/master/lib/videojs.ads.js
This worked perfect until version 5 but now that I have wanted to migrate to version 6, this plugin no longer works, the log throws me the following error:
TypeError: videojs.getComponent(...) is undefined videojs.ads.js:386
It seems that everything lies in this section of the plugin (line 386):
(function() {
var
videoEvents = videojs.getComponent('Html5').Events,
i,
returnTrue = function() { return true; },
triggerEvent = function(type, event) {
// pretend we called stopImmediatePropagation because we want the native
// element events to continue propagating
event.isImmediatePropagationStopped = returnTrue;
event.cancelBubble = true;
event.isPropagationStopped = returnTrue;
player.trigger({
type: type + event.type,
state: player.ads.state,
originalEvent: event
});
},
The plugin has not been updated since a while ago so I also gave some alarms on how to register the plugin but that yes I could solve it, I'm not very understanding of javascript so I do not know how I could solve that.
Ok comrades, I have been reading the manual of videojs 6 and apparently to solve that problem only had to change a line:
videojs.getComponent -to- videojs.getTech
I leave it here in case someone has the same problem.
Of course, I am not a Javascript specialist so I honestly would not know how to give an explanation about this.
I wrote a firefox extension and for interation data between privilege and non-privilege pages I use this snipped code
//Listen for the event
window.addEventListener("MyEvent", function(evt) {
console.log(evt.detail);
}, false);
//Dispatch an event
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent("MyEvent", true, true, {
name : 'activate',
method : function() {
//...
}
});
window.dispatchEvent(evt);
and everything go well after I update my FireFox to version 32.0.1, at this time my FireFox doesn't work and I try to find the error and discover that the method I passed to MyEvent always null. Why?
Is it possible that in the new version of FireFox I couldn't pass function any more or I should do something newer for solve my problem?
You probably have to use __exposedProps__.
Like
var detail = {
name: "activate",
method: function(){},
__exposedProps__: {method: "r"}
};
Needless to say that, unless you are absolutely sure that you know what you 're doing, this is a security risk.
Are you sure things used to work before?
You need to set the 4th argument of addEventListener to true. Argument is called wantsUntrusted.
MDN :: addEventListener
Also see this topic here: How to listen to custom events on all windows, bubbling issue?
So try this:
//Listen for the event
window.addEventListener("MyEvent", function(evt) {
console.log(evt.detail);
}, false, true);
//Dispatch an event
var evt = document.createEvent("CustomEvent");
evt.initCustomEvent("MyEvent", true, true, {
name : 'activate',
method : function() {
//...
}
});
window.dispatchEvent(evt);
I am writing tests for an AngularJS directive which fires events of a <textarea> when certain keys are pressed. It all works fine per my manual testing. I want to be good and have a full unit-test suite too, but I have run into a problem I can't solve on my own:
I want to send a specific keyCode in my triggerHandler() call in my test, but I can't find a way to specify the key that actually works. I am aware of a lot of questions and answers on the topic of building and sending events with specific data, but none of them work on my setup:
My setup
Karma test runner
PhantomJS browser running the tests (but also tried Firefox and Chrome without success)
I'm not using jQuery and I'm hoping there is a regular JS solution. There must be!
Test code
var event = document.createEvent("Events");
event.initEvent("keydown", true, true);
event.keyCode = 40; // in debugging the test in Firefox, the event object can be seen to have no "keyCode" property even after this step
textarea.triggerHandler(event); // my keydown handler does not fire
The strange thing is, I can type the first 3 lines into the console in Chrome and see that the event is being created with the keyCode property set to 40.
So it seems like it should work.
Also, when I call the last line like this textarea.triggerHandler("keydown"); it works and the event handler is triggered. However, there is no keyCode to work with, so it is pointless.
I suspect it may be something to do with the nature of the test running against a DOM that is different to a regular page running in the browser. But I can't figure it out!
I've used the following solution to test it and having it working in Chrome, FF, PhantomJS and IE9+ based on this SO answer.
It doesn't work in Safari - tried millions of other solution without any success...
function jsKeydown(code){
var oEvent = document.createEvent('KeyboardEvent');
// Chromium Hack: filter this otherwise Safari will complain
if( navigator.userAgent.toLowerCase().indexOf('chrome') > -1 ){
Object.defineProperty(oEvent, 'keyCode', {
get : function() {
return this.keyCodeVal;
}
});
Object.defineProperty(oEvent, 'which', {
get : function() {
return this.keyCodeVal;
}
});
}
if (oEvent.initKeyboardEvent) {
oEvent.initKeyboardEvent("keydown", true, true, document.defaultView, false, false, false, false, code, code);
} else {
oEvent.initKeyEvent("keydown", true, true, document.defaultView, false, false, false, false, code, 0);
}
oEvent.keyCodeVal = code;
if (oEvent.keyCode !== code) {
console.log("keyCode mismatch " + oEvent.keyCode + "(" + oEvent.which + ") -> "+ code);
}
document.getElementById("idToUseHere").dispatchEvent(oEvent);
}
// press DEL key
jsKeydown(46);
Hope it helps
Update
Today I've found and tested this solution which is offers a much wider coverage of browsers (enabling the legacy support):
https://gist.github.com/termi/4654819
All the credit goes to the author of this GIST.
The code does support Safari, PhantomJS and IE9 - tested for the first 2.
Adding to #MarcoL answer, I'd like to point out for future readers who might stumble on this question, that the methods initKeyboardEvent and initKeyEvent are deprecated methods, and should no longer be used. See here and here.
Instead as the MDN docs suggested, events should be created via their respective constructor.
I would like to write some tests for some input filtering code in a text box. For most tests, I can just call setValue and trigger the change event, which is easy to do. However, in this case, because I want to test that the input gets filtered out (or not), I can't just setValue() directly.
I tried dispatching keydown, keyup, keypress, textinput events. I can see that the handlers for them are being called, but the text doesn't actually show in the text box Note that this only "works" in Firefox, I understand the code would look different for other browsers.
function dispatch(target, eventType, charCode) {
var evt = document.createEvent("KeyboardEvent");
evt.initKeyEvent(
eventType,
true,
true,
window,
false,
false,
false,
false,
charCode,
0
);
target.dispatchEvent(evt);
}
var id = document.getElementById('id');
id.onkeydown = id.onkeyup = id.onkeypress = function() {console.log(arguments)}
dispatch(id, 'keydown', 65);
dispatch(id, 'keyup', 65);
dispatch(id, 'keypress', 65);
dispatch(id, 'textinput', 65);
// I can see the handlers were called but it doesn't display in the text box
I understand this has restrictions because we don't want web apps to just pretend like they are acting for the user. However, this is for testing my own application and I could launch Firefox with a specific profile and install plugins, or even write my own if I know it will help.
What I am after is to avoid using Selenium, I want to keep Java out of my JS tests because not only is it slow, but I have to re-implement a lot of the DOM querying in Java.
After all this, the question is, does anybody know how to get that code to actually modify the input? Tweaking settings, installing plugins?
List of questions that don't answer my question
Simulating user input for TDD JavaScript
Definitive way to trigger keypress events with jQuery
How to send a key to an input text field using Javascript?
Is it possible to simulate key press events programmatically?
I just found out that the following code does work in Chrome at least. No go in firefox or IE http://jsfiddle.net/D2s5T/14/
function dispatch(target, eventType, char) {
var evt = document.createEvent("TextEvent");
evt.initTextEvent (eventType, true, true, window, char, 0, "en-US");
target.focus();
target.dispatchEvent(evt);
}
dispatch(el, "textInput", "a");
I am currently building a browser extension that injects javascript/jquery into certain pages, and i am having a weird issue, where forcing .click() events are not working from my injected code. The strange bit is that it works completely fine if i make the call from my console js console.
I dont really understand what the problem is. It seems that all of my other calls are working fine. I can bind to click events using .click(function(){...}) (so clearly my jquery has been loaded properly), and call methods when things are clicked (so clearly my jquery has been loaded properly), but the second that i try to force a click, the call just does not go through.
Can anybody explain what is happening, or a way that i can get around it?
(i can not recreate this issue, because the problem clearly has to do with injecting the js in an extension)
this is the best i can do for recreation:
//I have tried all of these separately
console.log($("#this_is_an_id")) //This returns the correct element
$("#this_is_an_id").click() //This does not work at all
$("#this_is_an_id").trigger("click") //I have also tried this without success
$("#this_is_an_id").click(function(){ console.log("stuff") }) //This works fine.
Really, at this point, i am assuming it is not my fault, but something that is wrong with the browser's method of injecting script. I am sorta looking for really hackey ways to fix this, i also tried eval('$("#this_is_an_id").trigger("click")'). Does anybody have any other suggestions?
I finally found a very excellent answer/work around to this issue here:
Trigger events from Firefox browser extension?
From user cms:
First of all, for click events, you need to create an event object with type MouseEvents, not HTMLEvents, and use event.initMouseEvent instead of event.initEvent.
To access the document of the current tab of Firefox from a XUL overlay, you can use the content.document property, but since you already have access to the DOM element you want to click, you can use the Node.ownerDocument property, which will refer to the top-level document object for this node.
I have made a simple function to simulate MouseEvents:
function triggerMouseEvent(element, eventName, userOptions) {
var options = { // defaults
clientX: 0, clientY: 0, button: 0,
ctrlKey: false, altKey: false, shiftKey: false,
metaKey: false, bubbles: true, cancelable: true
// create event object:
}, event = element.ownerDocument.createEvent("MouseEvents");
if (!/^(?:click|mouse(?:down|up|over|move|out))$/.test(eventName)) {
throw new Error("Only MouseEvents supported");
}
if (typeof userOptions != 'undefined'){ // set the userOptions
for (var prop in userOptions) {
if (userOptions.hasOwnProperty(prop))
options[prop] = userOptions[prop];
}
}
// initialize the event object
event.initMouseEvent(eventName, options.bubbles, options.cancelable,
element.ownerDocument.defaultView, options.button,
options.clientX, options.clientY, options.clientX,
options.clientY, options.ctrlKey, options.altKey,
options.shiftKey, options.metaKey, options.button,
element);
// dispatch!
element.dispatchEvent(event);
}
Usage:
triggerMouseEvent(element, 'click');
Check a test usage here.
You can pass also an object as the third argument, if you want to change the values of the event object properties.
Thank you so much for this answer. O_O