Reputation: 91
Description: I want to read a particular label from the webpage, whose value changes to one of "started", "inprogress", "success", "Error". Once the label value changes to "success" or "Error" there will not be any further changes.
Issue: When I read the label value using javascript in protractor, the text value of the label is not returned to the calling function; instead it returns 'undefined'. Below is my code, please have a look and let me where the issue is.
CheckColor_Test.js
var commonFunctions = require('../pages/CommonFunctions.js');
describe("Run Test", function () {
it("should stop once the status reached Success or Error", function () {
var processStatus = commonFunctions.refreshTillProcessFinish();
expect(processStatus).toContain('Success','Error');
});
});
CommonFunctions.js
Var CommonFunctions = function(){
var label = element(by.id('Status'));
var refreshStatusBtn = element(by.css('[ng-click="getJob()"]'));
this.getStatusValue = function () {
return label.then(function (headers) {
return headers.getText();
});
};
this.refreshTillRefreshFinish = function () {
var refreshStatusMonitor = function (currentStatus) {
return currentStatus.then(function (Status) {
if (Status == 'Success' || Status.includes("Error")) {
console.log(Status);
return Status;
} else {
refreshStatusBtn.click();
console.log(Status);
browser.sleep(2000);
refreshStatusMonitor (currentStatus);
}
});
};
return refreshStatusMonitor (this.getStatusValue);
};
}
module.exports = new CommonFunctions();
Executing in Protractor: I have configured protractor in Webstorm, hence I used to run using that.
Expected Result: The test should get successful and passed
Actual Result: The test fails with below error.
"C:\Program Files (x86)\JetBrains\WebStorm 2016.1.1\bin\runnerw.exe" "C:\Program Files\nodejs\node.exe" node_modules\protractor\built\cli.js D:\Somesh_HDD\WebstormProjects\ProjectUBET\conf.js
[22:19:59] I/direct - Using ChromeDriver directly...
[22:19:59] I/launcher - Running 1 instances of WebDriver
Spec started
Started
InProgress
Success
Run Test
? should stop once the status reached Success or Error
- Expected undefined to contain 'Success', 'Error'.
**************************************************
* Failures *
**************************************************
1) Run Test should stop once the status reached Success or Error
- Expected undefined to contain 'Success', 'Error'.
Executed 1 of 1 spec (1 FAILED) in 33 secs.
[22:20:36] I/launcher - 0 instance(s) of WebDriver still running
[22:20:36] I/launcher - chrome #01 failed 1 test(s)
[22:20:36] I/launcher - overall: 1 failed spec(s)
[22:20:36] E/launcher - Process exited with error code 1
Process finished with exit code 1
Upvotes: 1
Views: 302
Reputation: 4832
Is your script able to click on the refresh button recursively?
i have made few changes to your existing script by introducing promises inside the recursive method.Just give a try.
var CommonFunctions = function(){
var label = element(by.id('Status'));
var refreshStatusBtn = element(by.css('[ng-click="getJob()"]'));
this.refreshTillRefreshFinish = function () {
var defer = protractor.promise().defer();
var refreshStatusMonitor = function () {
label.getText().then(function (Status) {
if (Status == 'Success' || Status.includes("Error")) {
defer.fulfill(Status);
} else {
refreshStatusBtn.click();
browser.sleep(2000);
refreshStatusMonitor ();
}
});
return defer.promise;
};
return refreshStatusMonitor ();
};
}
module.exports = new CommonFunctions();
Upvotes: 0
Reputation: 350270
The following return value:
return currentStatus.then(...);
is not the value returned by this statement:
return Status;
In fact, the latter is returned to one of the recursive calls of refreshStatusMonitor
which is not captured anywhere.
Because this is asynchronous code involving promises, the return value of currentStatus
should be a promise as well, which would bubble up via refreshStatusMonitor
, refreshTillRefreshFinish
to your test, which then also needs to be adapted to wait for the promise to be fulfilled before expecting anything.
I would also advise against the use of browser.sleep(...)
as it completely blocks your JavaScript environment. You could use setTimeout(...)
instead.
Here is some untested code which builds on those ideas:
this.refreshTillRefreshFinish = function () {
// create a promise
var deferred = protractor.promise.defer();
var refreshStatusMonitor = function (currentStatus) {
currentStatus.then(function refresh(Status) {
if (Status == 'Success' || Status.includes("Error")) {
// Signal the completion via the promise.
// This triggers the `then` callback in your revised test
deferred.fulfill(Status);
} else {
refreshStatusBtn.click();
console.log(Status);
// Use setTimeout so JavaScript is not blocked here:
setTimeout(function () {
refreshStatusMonitor(currentStatus);
}, 2000);
}
});
};
refreshStatusMonitor(this.getStatusValue);
// Don't wait for the result to happen while blocking everything,
// instead return a custom-made promise immediately
return deferred.promise;
};
Your test should then also take into account that you are dealing with a promise:
it("should stop once the status reached Success or Error", function () {
var processStatus = commonFunctions.refreshTillProcessFinish().then(function () {
expect(processStatus).toContain('Success','Error');
done();
});
}, 20000); // set timeout to 20 seconds
Note that Jasmine has a default timeout of 2 seconds, so you need to provide that extra argument at the end.
NB: Such asynchronous tests are not very suitable for running batches of unit tests.
Upvotes: 1