stimms
stimms

Reputation: 44094

CasperJS proceeding to next step too soon before event callbacks have finished

I have some casperjs tests which are running beautifully locally. When I move them up into TeamCity and run them against a staging server I'm seeing intermittent failures.

It looks to me like casper is clicking on a button and then not waiting for the JavaScript behind that button to fully execute before moving onto the next step. The JavaScript behind the button does some stuff then posts back (it is webforms, ugh).

In the log I see the click event firing, then the next step with a test in it starts then the navigation occurs(last line).

[info] [phantom] Step _step 8/9 http://site.azurewebsites.net/job.aspx (HTTP 200)
[debug] [phantom] Mouse event 'mousedown' on selector: .save-button
[debug] [phantom] Mouse event 'mouseup' on selector: .save-button
[debug] [phantom] Mouse event 'click' on selector: .save-button
[info] [phantom] Step _step 8/9: done in 2456ms.
[info] [phantom] Step anonymous 9/9 http://site.azurewebsites.net/job.aspx (HTTP 200)
FAIL Feedback exists
#    type: assertExists
#    file: Prime.WebSite.UITest\app.js
#    subject: false
#    selector: "#Feedback"
[info] [phantom] Step anonymous 9/9: done in 2857ms.
[debug] [phantom] Navigation requested: url=http://site.azurewebsites.net/job.aspx, type=FormSubmitted, willNavigate=true, isMainFrame=true

My casper, which is written in TypeScript, looks like

public TestCreatingBasicJob(casper: Casper) {
    casper.test.begin("Creating Basic Works", 3, (test: Tester) => {
        casper.start(baseUrl, () => {
            this.auth.LoginAsAdminUser(casper);
        });
        casper.thenOpen(baseUrl + "/jobs.aspx", () => {

        });
        casper.thenClick(".new-button");
        casper.then(() => {

        });

        casper.thenClick(".save-button");

        casper.then(() => {
            test.assertExists("#Feedback", "Feedback exists");
            var feedbackClass = casper.evaluate(() => $("#Feedback").attr('class'));
            test.assertEquals("success", feedbackClass, "Feedback is success");
            this.jobNumber = casper.evaluate(() => $("#JobNumber").text());
            test.assertNotEquals(this.jobNumber, null, "Job number populated: " + this.jobNumber);
        });

        casper.run(() => {
            auth.Logout(casper);
            test.done();
        });
    });
}

It compiles to

CreateJobTests.prototype.TestCreatingBasicJob = function (casper) {
        var _this = this;
        casper.test.begin("Creating Basic Works", 3, function (test) {
            casper.start(baseUrl, function () {
                _this.auth.LoginAsAdminUser(casper);
            });
            casper.thenOpen(baseUrl + "/jobs.aspx", function () {
            });
            casper.thenClick(".new-button");
            casper.then(function () {
            });

            casper.thenClick(".save-button");

            casper.then(function () {
                test.assertExists("#Feedback", "Feedback exists");
                var feedbackClass = casper.evaluate(function () {
                    return $("#Feedback").attr('class');
                });
                test.assertEquals("success", feedbackClass, "Feedback is success");
                _this.jobNumber = casper.evaluate(function () {
                    return $("#JobNumber").text();
                });
                test.assertNotEquals(_this.jobNumber, null, "Job number populated: " + _this.jobNumber);
            });

            casper.run(function () {
                auth.Logout(casper);
                test.done();
            });
        });
    };

How can I avoid the next step firing before the navigation is requested? I've tried manually setting casper.navigationRequested=true both in the step before the thenClick and in the callback from the thenClick but the flag never seems to be cleared so the test hangs.

It could probably be fixed just by waiting but it was my impression that a call to casper.wait was something of an anit-pattern.

Upvotes: 1

Views: 1127

Answers (1)

Jakub Kania
Jakub Kania

Reputation: 16487

CasperJS provides a whole lot of functions you can use to determine if it's time to move on already all named waitFor . Depending on what your webforms do you could use waitForSelector() to wait till the webform appears or waitWhileSelector() to wait till the loading animation disappears or one of the others. You just need to observe what changes.

Upvotes: 1

Related Questions