简体   繁体   中英

issue in recursive call of javascript

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

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.

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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM