Nightwatch - wait for text of an element - javascript

I am new to Nightwatch & JavaScript and need some help with a nightwatch test: Here is what I want to do:
Step 1.refresh browser,
Step 2. check textValue of an element .
Repeat step1 then step2 until given timeout or textValue of element is same as expected value.
I have been trying to use while looping, however it didn't solve the problem. Here is what I have been working on for some time now.
function waitForText(browser) {
var sent = false;
var time = new Date();
time.setTime(Date.now());
while (!sent && (new Date().getTime() - time) < browser.timeout * 30) {
var status = "Sending";
browser.refresh();
browser.getText('#elementId', function (result) {
status = result.value;
if (status.indexOf("Sent") == 0) {
sent = true;
}
});
}
}

Related

javascript function move to webworker

I have function:
function addModel() {
var values = new Array();
var $input = $('input[type=\'text\']');
var error = 0;
$input.each(function() {
$(this).removeClass('double-error');
var that = this;
if (that.value!='') {
values[that.value] = 0;
$('input[type=\'text\']').each(function() {
if (this.value == that.value) {
values[that.value]++;
}
});
}
});
$input.each(function(key) {
if (values[this.value]>1) {
//error++;
var name = this.value;
var product_model = $(this).parent().parent().find('.product-model').text();
var m = product_model.toLowerCase().areplace(search,replace);
$(this).parent().find('input[type=\'text\']').val(name + '-' + m);
}
});
return error <= 0; //return error > 0 ? false : true;
}
where are a lot of inputs to recheck... up to 50000. Usually are about 5000 to 20000 inputs. Of course browsers are freezing... How to move this function to web-worker and call it to get data back and fill form type="text"
thank you in advance.
Web workers don't have direct access to the DOM. So to do this, you'd need to gather the values of all 5-50k inputs into an array or similar, and then send that to the web worker (via postMessage) for processing, and have the web worker do the relevant processing and post the result back, and then use that result to update the inputs. See any web worker tutorial for the details of launching the worker and passing messages back and forth (and/or see my answer here).
Even just gathering up the values of the inputs and posting them to the web worker is going to take significant time on the main UI thread, though, as is accepting the result from the worker and updating the inputs; even 5k inputs is just far, far too many for a web page.
If maintaining browser responsiveness is the issue, then releasing the main thread periodically will allow the browser to process user input and DOM events. The key to this approach is to find ways to process the inputs in smaller batches. For example:
var INTERVAL = 10; // ms
var intervalId = setInterval((function () {
var values = [];
var $input = $('input[type=\'text\']');
var index;
return function () {
var $i = $input[index];
var el = $i.get();
$i.removeClass('double-error');
if (el.value != '') {
values[el.value] = 0;
$input.each(function() {
if (this.value == el.value) {
values[el.value]++;
}
});
}
if (index++ > $input.length) {
clearInterval(intervalId);
index = 0;
// Now set elements
intervalId = setInterval(function () {
var $i = $input[index];
var el = $i.get();
if (values[el.value] > 1) {
var name = el.value;
var product_model = $i.parent().parent().find('.product-model').text();
var m = product_model.toLowerCase().areplace(search,replace);
$i.parent().find('input[type=\'text\']').val(name + '-' + m);
}
if (index++ > $input.length) {
clearInterval(intervalId);
}
}, INTERVAL);
}
};
}()), INTERVAL);
Here, we do just a little bit of work, then use setInterval to release the main thread so that other work can be performed. After INTERVAL we will do some more work, until we finish and call clearInterval

RRule JS weekday property not working as expected

I have written following code for getting daily recurrence in my angular, my issue is when I use byweekday property of RRule JS, application stuck and does not respond at all. Sometimes it does work but takes huge time to execute code on line #rrule_after. Please let me know why is this happening and what can be better solutions for this?
function getNextRecurrenceDate(recurrenceVo,rule){
var startDate = new Date(recurrenceVo.recurrenceRangeVO.startDate);
var today = new Date();
var calculatedDate = null;
if(today.getTime() <= startDate.getTime()){
return startDate;
}else{
//#rrule_after - when I debug the code and comes to this function execution, my application stucks/halts for long time and does not response at all
calculatedDate = rule.after(today,true);
// this is temporary code I have written to overcome the problem of daily weekday recurrence
if(calculatedDate && recurrenceVo.dailyRecurrenceVO && recurrenceVo.dailyRecurrenceVO.everyWeekDay && calculatedDate.getDay() > 4){
calculatedDate.setDate(calculatedDate.getDate() + (7 - calculatedDate.getDay()));
}
}
return (calculatedDate)?calculatedDate:'';
}
function getDailyNextRecurrenceDate(recurrenceVo){
var rule = new RRule({
freq: RRule.DAILY,
interval: recurrenceVo.dailyRecurrenceVO.numberofDays,
dtstart: new Date(recurrenceVo.recurrenceRangeVO.startDate)
})
if(recurrenceVo.recurrenceRangeVO.endCount){
rule.options.count = recurrenceVo.recurrenceRangeVO.endCount;
}
if(recurrenceVo.dailyRecurrenceVO.everyWeekDay){
rule.options.interval = 1;
// When I remove this code then all working fine and application not halting at all
rule.options.byweekday = [RRule.MO, RRule.TU, RRule.WE, RRule.TH, RRule.FR]
}
if(recurrenceVo.recurrenceRangeVO.endDate){
rule.options.until = new Date(recurrenceVo.recurrenceRangeVO.endDate);
}
var nextRecDate = getNextRecurrenceDate(recurrenceVo,rule);
return nextRecDate?nextRecDate.setHours(0,0,0,0):'';
}

how can I add the ticking clock to my div in an existing code?

It's actually a follow up to this question I want to display elements from json based on their time and duration and interval is interupted by settimeout - I accepted the answer there made by #Daniel Flint - his code is quite clear and can be found here http://jsfiddle.net/nauzilus/rqctam5r/
However, there's one more thing that I wanted to add - a simple div <div id="time"></div> that would contain a new date time object initialized during opening the page and then it being incremented every second just to show the current time constantly. I thought about writing there a javascript:
var actualTime = new Date(substractedDate); // taken from the server
function updateTimeBasedOnServer(timestamp) {
var calculatedTime = moment(timestamp);
var dateString = calculatedTime.format('h:mm:ss A');
$('#time').html(dateString + ", ");
};
var timestamp = actualTime.getTime();
updateTimeBasedOnServer(timestamp);
setInterval(function () {
timestamp += 1000; // Increment the timestamp at every call.
updateTimeBasedOnServer(timestamp);
}, 1000);
(I provide the time of the server as a timestamp there).
I just noticed that there is a slight mismatch between displaying the time in my div and between the text appearing on the screen, possibly because I increment both of the values in two different places.
So my question is - how can I "merge" #Daniel Flint's code with mine and increment both values only in one place?
One thing that jumps out here:
timestamp += 1000;
setTimeout/setInterval aren't guaranteed to run at precisely the delay you've entered. Run this in your browsers console:
var last = Date.now(),
time = function() {
var now = Date.now();
console.log(now - last);
last = now;
},
id = setInterval(time, 1000);
On my Mac at home (Chrome/FireFox) it was anywhere from 990 to 1015. Windows machine at work is a bit better (995-1002), but IE was getting up to 1020. It's not a huge difference, but it's not nothing.
So code needs to be able to handle not running exactly every 1000ms. That's why I was running the timer at 500ms intervals, and checking if the start time was less-than-equal to the current time.
I've rejigged the demo to show the time and message in sync:
(function() {
var messages = [];
var time = document.getElementById("current-time");
var display = document.getElementById("message");
function check() {
showMessage(currentMessage());
showTime();
}
function currentMessage() {
var message = null;
if (messages.length) {
var now = toTheSecond(new Date());
var start = toTheSecond(new Date(messages[0].start_time));
var end = toTheSecond(new Date(start.getTime() + ( messages[0].text_duration * 1000 )));
if (start <= now) {
if (end <= now) {
// done with the current message...
messages = messages.slice(1);
// ...but check if there's another one ready to go right now
message = currentMessage();
}
else {
message = messages[0];
}
}
}
return message;
}
function toTheSecond(date) {
date.setMilliseconds(0);
return date;
}
function showMessage(message) {
if (message) {
display.textContent = message.text_content;
}
else {
display.textContent = "no messages";
}
}
function showTime() {
time.textContent = new Date().toLocaleString()
}
function getMessages() {
setTimeout(function() {
var now = new Date();
messages.push(
{"text_content":"aaaaa","text_duration":5,"start_time": new Date(now.getTime() + 3000).toISOString()},
{"text_content":"aawwaaaaa","text_duration":5,"start_time": new Date(now.getTime() + 10000).toISOString()},
{"text_content":"bbaawwaaaaa","text_duration":5,"start_time": new Date(now.getTime() + 15000).toISOString()}
);
}, 1000);
}
setInterval(check, 500);
getMessages();
})();
<span id="current-time"></span> <span id="message">Hello there!</span>
(Putting the code here as well because I recall SO want code in the answers so it's controlled, but there's a demo here: http://jsfiddle.net/nauzilus/ymp0615g/).
This probably isn't as efficient as it could be; the message text is being set every iteration which might cause repaints/reflow. But then again setting the time stamp is going to do that anyway, so meh :)

Candy Crush Saga Type countdown life system jQuery & Phonegap

I'm developing an app and I'm interested in ways to achive a Candy Crush Saga Type countdown life system.
My app is developed in phonegap (so html, css jquery and jquery mobile) and untill now I havn't figured out how to work with an external file as I'm thinking it's needed in this algorithm.
I want therefore to have 5 lives and each of them dissapears when the user fail or quit the lvl and regenerates after, lets say, 10 minutes. How can I keep the counter active if the app is closed?
Or a date substraction algorithm...
If somebody have knowledge in Phonegap I would be very grateful if he could help me with a jsfiddle wich I'll implement further in my app.
I'm also not sure what to use: localstorage vs DB
I'll give 50 of my bounty for the one who can help me with a jsfiddle example for this issue.
Thank you!
Edit: Sorry this is some pseudo code based off PHP - but you don't need crazy algorithms or anything
I don't write phone apps, but I know what you're trying to do and you're thinking about it too hard. You don't need to run the counter while the app is closed. You can save a timestamp from when the game is over, and reference it the next time the app is opened.
start_game();
if($lives > 0){ //run game
if($death === true){
$lives = $lives - 1;
$timer_value = date(Y-m-d h:i:s);
end_game($timer_value); //save starting time locally in "end_game" function
}
} else {
//buy more lives
}
Now let's say the user closes it and opens up. You can reference the current time versus the saved time. For every 10 minutes past then, add a life.
$old_time = strtotime($timer_value); //635393400
$cur_time = strtotime(date(Y-m-d h:i:s)); //635394600
if( $cur_time - $old time > 600 ) { $lives = $lives + 1; }
if( $cur_time - $old time > 1200 ) { $lives = $lives + 2; }
if( $cur_time - $old time > 1800 ) { $lives = $lives + 3; }
if( $cur_time - $old time > 2400 ) { $lives = $lives + 4; }
if( $cur_time - $old time > 3000 ) { $lives = $lives + 5; }
if( $lives > 5 ) { $lives = 5; }
That's some awful code lol, but you gut the idea. You don't need to run a timer in the background (you can't really with the app being closed, without doing some sort of server checks online, which is basically the same thing, but hosting all that personal life records in the cloud instead of on the phone.
In this code I use the localStorage since they are available on all platforms and web.
Using local storage you will get better cross platform compatibility:
WebStorage (localStorage & sessionStorage)
IndexedDB
SQL-Storage
Localstorage is array, but every element can only have string in it (using JSON we can store anything, that is not recursive). It is about 5MB for web. I guess it is limitless for mobile app. SessionStorage is deleted when user close browser and I am not sure how it will do on mobile.
Just a small date validator...
Date.prototype.isValid = function(first_argument) {
if ( Object.prototype.toString.call(this) !== "[object Date]" )
return false;
return !isNaN(this.getTime());
}
The main var declaration among retrieving variables from localStorage
var timeout = null;
var maxlife = 5;
if (undefined === localStorage.life) {
localStorage.life = maxlife;
}
if (undefined === localStorage.date||localStorage.date=="") {
localStorage.date = "";
var date = null;
}else{
var date = new Date(Number(localStorage.date));
if(!date.isValid()){
date = null;
}
}
var timeoutTime = 5 * 60000;
var life = Number(localStorage.life);
Lose life, set date if none exist yet. Set a timeout too and subtract life (& write it into localstorage).
function loseLife() {
if (null === date) {
date = new Date();
localStorage.date = date.getTime();
timeout = setTimeout(function(){addLife()}, timeoutTime);
}
life--;
localStorage.life = life;
lives.innerHTML = life;
console.log(life);
}
Add life, set date new date or reset the date completely. Set a timeout, if needed, and add a life (& write it into localstorage).
function addLife() {
life++;
localStorage.life = life;
if (life < maxlife) {
date = new Date();
localStorage.date = date.getTime();
timeout = setTimeout(function(){addLife()}, timeoutTime);
} else {
date = null;
localStorage.date = "";
}
lives.innerHTML = life;
}
Here you may need to change the hooks for blur (window not visible) and focus (window visible once again). Blur just clear timeout so it don't mess with us.
window.addEventListener('blur', function () {
clearTimeout(timeout);
});
This function check how many time it can subtract our time needed to get life from difference of now and the date we lost a life.
function tillNow(){
if (life < maxlife&&date!=null) {
var d = new Date();
var diff = d - date;
while (diff - timeoutTime > 0) {
diff = diff - timeoutTime;
if (life < maxlife) {
life++;
console.log("add");
}else{
date = null;
localStorage.date = "";
break;
}
}
localStorage.life = life;
if (life < maxlife) {
date = new Date((new Date()).getTime()-diff);
localStorage.date = date.getTime();
timeout = setTimeout(function(){addLife()}, timeoutTime-diff);
}
}
lives.innerHTML = life;
}
Focus just call tillNow()
window.addEventListener('focus', function () {
tillNow();
});
Onload do the same as focus, but fills the div with a value initially...
window.onload=function(){
var lives = document.getElementById("lives");
lives.innerHTML = life;
tillNow();
}
Demo sorry couldn't do jsFiddle of codepen since they don't like local storage. (the demo use 15sec as timer to get new life ;) I am impatient )
I would use logic similar to what Xhynk suggested. I would use a variable like milisecondsUntilYouGainALife and when you lose the first life, set this variable = 1000ms*60sec*10min = 600000. Then first line (or so) in main loop, record the current time. next time it hits the loop also record the time and subtract the difference from milisecondsUntilYouGainALife. If < 0, lives++. Also make sure in your "close the app" function you record the time and check that time in the main loop.
pseudocode:
function game(){
...
while(mainLoop){
oldTime = curTime
curTime = GetTime() //I Forget the exact code to get the miliseconds
deltaTime = curTime - oldTime
if(deltaTime > milisectionsUntilYouGainALife){
if(lives < MAX_LIVES){
lives++
milisecondsUntilYouGainALife - deltaTime
}
}
}
}
function AppClosing(){
curTime = GetTime()
}
function LoseALife(){
milisecondsUntilYouGainALife += 600000
}
There may be something im missing, but this should get you on the right track!

TypeError: Cannot call method "getThreads" of null. (line 59) + 1 other error

I have minimal knowledge of Javascript, but would like to use this code to enhance my GMail experience. It works, but I also get errors. When I run the debugger in Google Spreadsheet, two functions appear to malfunction:
TypeError: Cannot call method "getThreads" of null. (line 59)
With the following Execution transcript
GmailApp.getUserLabelByName([FollowUp])
GmailApp.getUserLabelByName([FollowUp/1undefined])
Inserted comment: there is some information about the GMail API call getThreads (and others) here: https://developers.google.com/apps-script/class_gmaillabel#getThreads
What I don't get is why it is calling Followup/1undefined -> why is it undefined? It should be Followup/1days
And another error with another function:
Cannot find method moveThreadsToInbox(. (line 26)
With nothing in the Execution transcript
The entire code is:
// Adapted from:
// http://gmailblog.blogspot.com/2011/07/gmail-snooze-with-apps-script.html
//
// To setup:
// - From the |Run| menu select |setup|
// - if prompted to authorize, do so, and then repeat this step.
//
// - Verify the script is set to be triggered to run
// - |Triggers| menu |Current script's triggers...|
// - 3 triggers should exist to call e.g.
// - dailyUpdate, Time Driven, Daily
function getLabelName(i, labelSuffixString) {
return "FollowUp/" + i + labelSuffixString;
}
function setup() {
for (var i = 1; i <= 7; ++i) {
GmailApp.createLabel(getLabelName(i, "days"));
GmailApp.createLabel(getLabelName(i, "weeks"));
}
GmailApp.createLabel("FollowUp");
}
function moveToInbox(page) {
GmailApp.moveThreadsToInbox(page);
GmailApp.markThreadsImportant(page);
}
function cleanOldFollowUpLabels() {
var searchString = "-label:inbox label:FollowUp";
for (var i = 1; i <= 7; ++i) {
searchString += " -label:" + getLabelName(i, "days");
searchString += " -label:" + getLabelName(i, "weeks");
}
searchString = searchString.replace(RegExp("/", "g"), "-");
Logger.log("cleanOldFollowUpLabels() Search String:");
Logger.log(searchString);
var followUpLabel = GmailApp.getUserLabelByName("FollowUp");
var page = null;
// Get threads in "pages" of 100 at a time
while(!page || page.length == 100) {
page = GmailApp.search(searchString, 0, 100);
Logger.log("found: " + page.length);
if (page.length > 0)
followUpLabel.removeFromThreads(page);
}
}
function update(labelSuffixString) {
var oldLabel, newLabel, page;
var followUpLabel = GmailApp.getUserLabelByName("FollowUp");
for (var i = 1; i <= 7; ++i) {
newLabel = oldLabel;
oldLabel = GmailApp.getUserLabelByName(getLabelName(i, labelSuffixString));
page = null;
// Get threads in "pages" of 100 at a time
while(!page || page.length == 100) {
page = oldLabel.getThreads(0, 100);
if (page.length > 0) {
followUpLabel.addToThreads(page);
if (newLabel) {
// Move the threads into "today’s" label
newLabel.addToThreads(page);
} else {
moveToInbox(page);
}
// Move the threads out of "yesterday’s" label
oldLabel.removeFromThreads(page);
}
}
}
}
function dailyUpdate() {
update("days");
}
function weeklyUpdate() {
update("weeks");
}
Also here: http://pastie.org/4790086.js
mm.. with the help of a colleague, we found the answer to my own problem. I had three triggers running: A daily trigger, a weekly trigger, and the update trigger. Now the update trigger was not necessary, because it was called upon by the daily and weekly trigger, and without any input. That caused the error. Now I have to wait and see if there are any errors and if the script works.

Categories