I need a repetitive block like while() that verifies a condition before being executed. My code is below, but the while doesn't work...
var foundPersonen = true;
while (foundPersonen) {
detailPage.getAllPersonen().then(function(value) {
if (value.length == 0) {
foundPersonen = true;
remoteControl(Keys.HK_BACK);
remoteControl(Keys.HK_P_up);
remoteControl(Keys.HK_INFO, 1, 3000);
}
else {
foundPersonen = false;
}
});
}
How can I replace the while but still have the same result I need?
I agree at least partially with alecxe. Some "wait" order should fix that. I just would like to explain my thought, hoping that it will be useful for you... Because I have spent a lot of time on this kind of problem^^.
The big point to me is that Protractor runs everything asynchronously.
When you run your test, Protractor basically runs every part of your code it can, i.e. until it encounters a promise. When it encounters a promise, Protractor could do two things, depending whether you have set browser.ignoreSynchronization = true; (this is my case)
If it's true, Protractor creates a new thread and wait for the promise to be resolved, but in the "main thread" Protractor continues to execute your code. If you want Protractor to wait for something, you will have to write it explicitly.
If it's false (this is the case by default), Protractor will add a browser.waitForAngular before continuing. But of course you can always add explicit waiting orders in your code, and you might want to do it in some cases to get a more stable code.
If you want more information about this, read this post
var foundPersonen = true;
while (foundPersonen){
detailPage.getAllPersonen().then(function(value) {
if (value.length == 0) {
foundPersonen = true;
remoteControl(Keys.HK_BACK);
remoteControl(Keys.HK_P_up);
remoteControl(Keys.HK_INFO, 1, 3000);
}
else {
foundPersonen = false;
}
}
In my case (browser.ignoreSynchronization = true;), this is what happens :
allocate one bit of memory for a boolean and set the value to 1;
evaluate the bit
If it is 1
Create a thread. In this thread, create a promise and wait for it to be resolved, then do something with the value of the promise
In the main thread, return to step 2
if it is 0, continue
This interpretation leads to a simple prediction. As the code that sets the value of the boolean to 0 is treated after the promise is resolved, this piece of code will create promises as fast as it can until one of these promises will be resolved and set the boolean to false.
The result of this ? Your code will reach the maximum of memory before the first promise will be resolved. --> You will receive some exception related to the allocation of memory.
I tested that with this code:
return scenariiSteps.AtlasLogin("my", "credentials")
.then(function () {
var foundDialogs = element.all(by.xpath("//div[#dialog-id]"));
var foundDialogsZero = true;
while (foundDialogs) {
foundDialogs.count().then(function (value) {
if (value == 0) {
foundDialogsZero = true;
console.log("0, man")
}
else {
console.log("Found something!")
foundDialogsZero = false;
}
});
}
});
What this code do is
Login
Allocate memory for some object (it will stock the list of the dialogs in the page of my app)
Allocate one bit of memory for a boolean and set it to false.
Evaluate the bit
if it is 1
create a promise and wait for it to be resolved, then do something with the value of the promise
return to step 4
And, to be sure of my interpretation, please note that my app contains 2 dialogs as soon as the user is logged in.
As I thought, I received FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
"Ok, thank you for that long explanation, but... What should I do now ?"
Well basically you have to tell to Protractor to wait for some condition before performing the action you want. The best way to do it depends on your requirements and your environment. For instance, I don't think the solution of alecxe would fix the problem in my environment.
It would be useful to know a bit more about what you want to do if you want more help.
Yeah, since protractor keep adding everything on to controlflow, blocks like while do not work as expected. Try calling it recursively in a function.
function keepChecking(){
while (foundPersonen) {
detailPage.getAllPersonen().then(function(value) {
if (value.length == 0) {
foundPersonen = true;
remoteControl(Keys.HK_BACK);
remoteControl(Keys.HK_P_up);
remoteControl(Keys.HK_INFO, 1, 3000);
keepchecking();
}
else {
foundPersonen = false;
}
});
}
}
keepchecking();
I think you can solve it with browser.wait():
browser.wait(function () {
return detailPage.getAllPersonen().count().then(function (count) {
if (count == 0) {
remoteControl(Keys.HK_BACK);
remoteControl(Keys.HK_P_up);
remoteControl(Keys.HK_INFO, 1, 3000);
return false;
}
else {
return true;
}
}
}, 10000);
This would execute the condition function up to 10 seconds while the count is 0. If it is 0, it executes your remote control functions. Please test.
Related
Suppose I have a collection of 4 steps.
I need to add an assertion to return success if last step is reached, and fail if collection execution have interrupted for some reason.
Based on your 4th request status code, you can do your assertion/your actions.
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
if you want to pass/fail the request manually, you should do,
tests["Status code is 200"] = true; // pass
tests["Status code is 200"] = false; // fail
I can not find anything on this so I decided to ask it here.
I am using react-native and redux.
I left the business logic out of the code.
I have this function which calls another function that does an API call.
The function that does the API call needs to access "getState", that's the reason I use dispatch.
const getStuff = (day) => (dispatch) => {
const result = await dispatch(functionThatDoesAPIRequest(day)
}
Then I have this code that loops over days and in some cases needs to do the API call. In the case I was testing it does not need to access the API. I could not find the problem with my code until I placed the line between the if statement in comments. Then I changed the if to always be False and the error persisted when the line of code was not in comments, even though it could never reach that piece of code.
for (let i = 0; i < dayArray.length; i+=1) {
if (false) {
const resultThatIsNotNeeded = await dispatch(getStuff(dayArray[i])
}
// more business logic
}
Changing the for loop to a ForEach loop fixed this issue somehow. But I really have no clue why this fixed it.
dayArray.forEach(async (day, i) => {
if (false) {
const resultThatIsNotNeeded = await dispatch(getStuff(dayArray[i])
}
}
That is because on your forEach the await call is inside of a async function as it should be
On the for loop I don't see any of this code being executed within a async function
i have a task to enter the notification date using protractor
where i need to clear contents before entering so i have came up with this code
this.Then(/^I should enter "Notification Date"$/, () => {
const d = new Date();
return orderCheckOutPage.pageElements.recipientNotificationDateMonth.clear().then(() => {
return orderCheckOutPage.pageElements.recipientNotificationDateMonth.sendKeys(d.getMonth() + 1).then(() => {
return orderCheckOutPage.pageElements.recipientNotificationDateDay.clear().then(() => {
return orderCheckOutPage.pageElements.recipientNotificationDateDay.sendKeys(d.getDate()).then(() => {
return orderCheckOutPage.pageElements.recipientNotificationDateYear.clear().then(() => {
return orderCheckOutPage.pageElements.recipientNotificationDateYear.sendKeys(d.getFullYear())
})
})
})
})
})
});
my friend told me the above code be can refactored as
const promises = [];
promises.push(orderCheckOutPage.pageElements.recipientNotificationDateMonth.clear());
promises.push(orderCheckOutPage.pageElements.recipientNotificationDateMonth.sendKeys(d.getMonth() + 1));
promises.push(orderCheckOutPage.pageElements.recipientNotificationDateDay.clear());
promises.push(orderCheckOutPage.pageElements.recipientNotificationDateDay.sendKeys(d.getDate()));
promises.push(orderCheckOutPage.pageElements.recipientNotificationDateYear.clear());
promises.push(orderCheckOutPage.pageElements.recipientNotificationDateYear.sendKeys(d.getFullYear()));
return promise.all(promises);
I heard promise.all will start resolving promises one by one
first it would go to first statement and try to resolve if it [here in the above case is clear month] if is asynch the it would jump to second one and try to execute the statement [sending keys to month]
here both the tasks of clearing and entering will be run parallely
and tasks are executed based on the time promises get resolved
if it is that case will there be chances of sendkeys being exeuted before clearing
correct me if i am wrong...!!!!!
Protractor has its own promise manage mechanism called control flow, To understand control flow simply, you can think it is a queue.
When nodejs execute your Protractor script line by line, if the expression in the line return a promise, control flow will add the promise into the queue.
After all lines execute done, you will get a promise queue, at this time point your testing had not finish yet, because control flow will make your testing to wait all promise in the queue be executed. Now control flow will pop a promise from the queue and execute and wait it complete, then next promise.
So with such mechanism, your script can be executed as the order as you write
down in file. Actually what control flow did is more complex than I said here.
You no need to use nested then chain in your case, your code like the callback pyramid, not represent the advantage of promise (promise is to resolve callback pyramid). Your code can be simple as below:
const d = new Date();
//input month
orderCheckOutPage.pageElements.recipientNotificationDateMonth.clear();
orderCheckOutPage.pageElements.recipientNotificationDateMonth.sendKeys(d.getMonth() + 1);
//input day
orderCheckOutPage.pageElements.recipientNotificationDateDay.clear();
orderCheckOutPage.pageElements.recipientNotificationDateDay.sendKeys(d.getDate());
//input year
orderCheckOutPage.pageElements.recipientNotificationDateYear.clear();
orderCheckOutPage.pageElements.recipientNotificationDateYear.sendKeys(d.getFullYear());
For your case, no need to use promise.all(), because all interaction of your code not to get some value from page. I will give an example to help you learn in which case it's better to use promise.all():
Assume i have a page and it display a price and a amount. I need to calculate the fee by price * amount.
Use nested then chain:
var fee = ele_price.getText().then(function(price){
return ele_amount.getText().then(function(amount){
return price * amount;
});
});
fee.then(function(fee){
console.log(fee);
});
Use promise.all():
var fee = promise.all([
ele_price.getText(),
ele_amount.getText()
])
.then(function(datas){
var price = datas[0];
var amount = datas[1];
return price * amount;
});
fee.then(function(fee){
console.log(fee);
});
So use promise.all(), one then() is enough. This makes your code more readable than nested then chain.
Hope you now understand why no need to use promise.all() in your case.
I am attempting to run the below listed function in Node on a VM with 3.5GB of memory. The query I am running returns ~2.25 million rows. It fails due to what appears to be a memory leak - if someone has encountered this or has suggestions on how to handle the increasing memory problem on this call, I'd appreciate it.
var sqlite3 = require('sqlite3').verbose();
db.each(query, function (error, data) {
if (error) {
console.log('Failed.');
} else {
console.log('Current perf: ', process.memoryUsage());
}
error = null; data = null;
}, function (error, responseLength) {
console.log('done with all');
});
Each row looks like this:
2015-11-13T01:17:32Z|510|40.632087|-73.946855|315.47|2|20151112|9910715-SCPD5-SC_D5-Weekday-10-SDon|0|307840|73.51|5.53
The goal is to handle each row one at a time and write them to a CSV, line by line, via a stream. The thought was that, by doing this, I would avoid having to hold the entire query response in memory - but this goal seems to be thwarted given the current situation.
I think you need to use a prepared statement and setImmediate(), like this:
var sqlite3 = require('sqlite3').verbose();
var stmt = db.prepare(query);
doQuery();
function doQuery(){
stmt.get(function(error, data){
if(data){
if(error){
console.log(error);
} else {
// do something with data here.
}
setImmediate(function(){
doQuery();
});
}
});
}
Explanation:
1) Prepared statements makes the client retrieve each row separately, rather than trying to grab all the results at once. The data param will be undefined when it hits the last row.
2) setImmediate() makes sure that the callback loop isn't called recursively, which could blow your call stack if the number of rows is too high.
For some reason, my code is unable to retrieve the IAsyncOperation object that is returned upon calling captureFileAsync method of the Windows.Media.Capture.CameraCaptureUI() method. The IAsyncOperation object is returned according to this documentation. In that documentation link, it states:
Return value
Type: IAsyncOperation<StorageFile>
When this operationcompletes, a StorageFile object is returned.
So here is my code:
var dialog = new Windows.Media.Capture.CameraCaptureUI();
var aspectRatio = { width: 4, height: 3 };
dialog.photoSettings.croppedAspectRatio = aspectRatio;
appSession.InAsyncMode = dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).done(function (file) {
if (file) {
self.addPage(URL.createObjectURL(file));
} else {
WinJS.log && WinJS.log("No photo captured.", "sample", "status");
}
}, function (err) {
// None taken
});
When I inspect the value of appSession.InAysncMode, I see that the function returns undefined. I suspect it returns undefined because the operation is not complete (i.e. the user has not yet created the photo, and it has not been saved to disc), but I need it in order to cancel out of the camera capture mode programmatically. Does anybody know why it would return undefined instead of the documented IAsyncOperation object?
Thanks!
For reference, here's the answer I posted on the MSDN forum.
To answer your ending question, you can cancel the capture UI by canceling the promise from dialog.captureFileAsync.
Your InAsyncMode flag is undefined because you're assigning to it the return value from captureFileAsync.done() which is, by definition, undefined. It has nothing to do with the API's success.
In the docs, when you see IAsyncOperation, what you get in JavaScript is a promise that will deliver as a result to the completed handler if it succeed. You never see IAsyncOperation or related interfaces in JavaScript directly. The documentation for WinRT is written to be language-neutral, so it's important to understand how those things show up in JS (as promises). In C# you don't see it either, as you just use the await keyword. It's mostly in C++ that you actually encounter the interface.
Anyway, you I believe you want is something along the lines of the code below, where you could eliminate IsAsyncMode in favor of just checking for a non-null promise:
appSession.capturePromise = dialog.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo);
appSession.IsAsyncMode = (appSession.capturePromise != null);
//This will close the capture UI after 5 seconds--replace with whatever logic you need
setTimeout(function () { appSession.capturePromise.cancel(); }, 5000);
appSession.capturePromise.done(function (file) {
if (file) {
} else {
}
}, function (err) {
appSession.IsAsyncMode = false;
appSession.capturePromise = null;
});