Javascript code not being executed in Nightwatch - javascript

I have a problem in regards to using .execute in Nightwatch.
When I run this code in the DOM, it works perfectly. However when I wrap it in an execute command in Nightwatch, it does not even make it to the first click. So probably the execute command is never being executed.
What am I doing wrong?
Thanks in advance
LoopThroughQuestions: function() {
this.waitForElementVisible('.next-button', constants.timeout.medium);
this.api.execute(function() {
var checkQuestion = function() {
var nextButton = document.querySelector('.next-button');
var answers = document.querySelectorAll('.flex-row.key');
answers[0].click();
nextButton.click();
setTimeout(function () {
if (document.querySelector('.next-button')) {
checkQuestion();
} else {
console.log("Exit");
}
}, 2000, "Running")
}
}, []) ;
return this;
},

You have defined the variable checkQuestion as a function, but you never call that function.
Try something like this:
LoopThroughQuestions: function() {
this.waitForElementVisible('.next-button', constants.timeout.medium);
this.api.execute(function() {
var checkQuestion = function() {
var nextButton = document.querySelector('.next-button');
var answers = document.querySelectorAll('.flex-row.key');
answers[0].click();
nextButton.click();
setTimeout(function () {
if (document.querySelector('.next-button')) {
checkQuestion();
} else {
console.log("Exit");
}
}, 2000, "Running")
checkQuestion();
}
}, []) ;
return this;
},
Recall that you can use a self invoking, anonymous function, too.
(function () {
// body of the function
}());

For people who experience the same problem; I fixed it with executeAsync, the script was being executed but the waiting on an element was insufficient
TestLoop: function() {
this.waitForElementVisible('.next-button', constants.timeout.medium);
this.api.executeAsync(function() {
let checkQuestion = function() {
let nextButton = document.querySelectorAll('.next-button');
let answers = document.getElementsByClassName('flex-row');
let blueButton = document.querySelectorAll('.blue-inverse-button').length;
answers[0].click();
nextButton[0].click();
setTimeout(() => {
if (document.querySelectorAll('.next-button')) {
console.log('Answering another question!');
checkQuestion();
}
if (blueButton === 1){
blueButton[0].click()
checkQuestion()
}
else {
console.log("Exiting?");
}
}, 2000);
};
// Initiating the check question function
return checkQuestion();
},[], function(){
console.log('Done?')
});
},

Related

How to execute code not from string using function?

How would I execute code not from a string? Here is an example:
var ready = false;
executeWhen(ready == true, function() {
console.log("hello");
});
function executeWhen(statement, code) {
if (statement) {
window.setTimeout(executeWhen(statement, code), 100);
} else {
/* execute 'code' here */
}
}
setTimeout(function(){ready = true}, 1000);
Could I use eval();? I don't think so, I think that's only for strings.
You call it with code().
You need to change statement to a function as well, so it will get a different value each time you test it.
And when you call executeWhen() in the setTimeout(), you have to pass a function, not call it immediately, which causes infinite recursion.
var ready = false;
executeWhen(() => ready == true, () =>
console.log("hello"));
function executeWhen(statement, code) {
if (!statement()) {
window.setTimeout(() => executeWhen(statement, code), 100);
} else {
code();
}
}
setTimeout(function() {
ready = true
}, 1000);

Aframe pass variables between functions in component

I’m trying to stop the throttledFunction from running unless the “fly” event listener has been emitted. But I can’t change the “this.ballhit” variable from inside the eventlistener.
I don’t know how to pass variables between functions within the component.
AFRAME.registerComponent('ballflyact', {
init: function () {
var el = this.el;
this.ballhit = '';
el.addEventListener('fly', function () {
this.ballhit = true;
});
},
tick: function (t, dt) {
if (!this.ballhit) { return; }
this.throttledFunction(); // Called once a second.
},
});
When you create a function, this becomes different.
You can use self-binding function el.addEventListener('fly', () => { // ... });
Or like var self = this; el.addEventListener('fly', function () { self.ballHit = true; });
The following works. Thank you. Now the throttle function will only run for ~10,000 milliseconds after the “fly” event, not constantly in the background.
AFRAME.registerComponent('ballflyact', {
init: function () {
var el = this.el;
this.ballhit = '';
var self = this;
el.addEventListener('fly', function () {
self.ballhit = true;
// more code
setTimeout((e)=>{
self.ballhit = '';
}, 10000)
});
},
tick: function (t, dt) {
if (!this.ballhit) { return; }
this.throttledFunction(); // Called once a second.
},
});

Simple Javascript: How to invoke a function based off user prompt;

I've defined some functions, and I want to get user input to invoke those functions. I have the following code, but can't figure out how to invoke the actual function when I'm using a variable. I assumed below code would work..
thanks!
var someFunctions = {
play: function() {
if (player.stopped()) {
player.play();
} else {
return false;
}
}
var getCommand = function(){
var command = prompt("Please enter a command");
if (!(command in someFunctions)) {
alert('command not recognized');
getCommand();
} else {
command();
}
}
getCommand();
var someFunctions = {
play: function() {
if (player.stopped()) {
player.play();
}
else {
return false;
}
}
};
var getCommand = function(){
var commandInput = prompt("Please enter a command");
var command = someFunctions[commandInput];
if (!command) {
alert('command not recognized');
getCommand();
}
else {
command();
}
};
getCommand();
The reason your code isn't working is because you're missing the closing } of someFunctions.
var someFunctions = {
play: function() {
if (player.stopped()) {
player.play();
} else {
return false;
}
}
} // here
Your call is fine, you call a "variable" function the same way you do a regular one. The only difference between a "variable" function and an ordinary one is you can call the ordinary one before it's declared (if you're in the same scope at least)

How to reference a parent JavaScript function in a nested IIFE module? [duplicate]

This question already has answers here:
Javascript object literal, how to solve context?
(3 answers)
Closed 8 years ago.
Take the following code below... In the setTimeout anonymous function, what is the correct way to reference the alert.hide() method? Is it correct to just write out the whole call as admin.alert.hide();? or Is there a better way to reference admin without having to call it directly?
var admin = (function(jQuery, window, document, undefined) {
return {
loader : (function(admin) {
var fade = 75;
var loader = '#loader';
return {
show : function () {
jQuery(loader).stop().fadeIn(fade);
},
hide : function() {
jQuery(loader).stop().fadeOut(fade);
}
}
})(),
alert : (function() {
var timeout;
var fade = 500;
var milliseconds = 1000;
var alert = '#alert';
return {
timeout : timeout,
show : function(message) {
jQuery(alert).find('p').text(message);
jQuery(alert).stop().fadeIn(fade);
clearTimeout(this.timeout);
this.timeout = setTimeout(function() { }, milliseconds);
},
hide : function() {
jQuery(alert).stop().fadeOut(fade);
}
}
})()
}
})(jQuery, window, document);
You could do the following:
return
{
timeout : timeout,
show : function(message)
{
jQuery(alert).find('p').text(message);
jQuery(alert).stop().fadeIn(fade);
clearTimeout(this.timeout);
this.timeout = setTimeout((function() { this.hide(); }).bind(this), milliseconds);
},
hide : function()
{
jQuery(alert).stop().fadeOut(fade);
}
}

Killing setInterval upon object deletion

I have the following HTML page:
<html>
<script>
var global = {};
global.obj = {
// when called this function will cause 'hello' to be output to the
// console every 1 second
repeat: function () {
setInterval(function () {
console.log('hello');
}, 1000);
}
}
global.obj.repeat();
global.obj = [];
// even after we overwrite global.obj, 'hello'
// continues to be output to the console every second
</script>
</html>
I want to write a function similar to repeat, except when global.obj is overwritten, setInterval will stop being called
You'll want to use getters/setters, Mozilla has some good docs on this.
You may have to tweak it a bit:
var intervalRef = null;
var global = {objRef: {}};
global.__defineSetter__("obj", function(o) {
if (intervalRef)
clearInterval(intervalRef);
intervalRef = null;
global.objRef = o;
});
global.__defineGetter__("obj", function() {
return global.objRef;
});
global.obj = {
repeat: function () {
intervalRef = setInterval(function () {
console.log('hello');
}, 1000);
}
}
global.obj.repeat();
setTimeout(function() { //this just demonstrates that you can let it run for 5 secs before clearing the timer.
global.obj = [];
}, 5000);
I tested this and verified that it works.
See this Fiddle:
// html
<p id="stopper">Click</p>​
// js
var counter = new Object();
counter.timer = setInterval( function(){
console.log("Hello!");
}, 1000 );
$("#stopper").click(function(){
console.log("Stopping");
clearInterval(counter.timer);
});
​

Categories