1

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.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
stimms
  • 42,945
  • 30
  • 96
  • 149

1 Answers1

1

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.

Jakub Kania
  • 15,665
  • 2
  • 37
  • 47
  • I was aware of those functions but they just felt dirty to me. If that is the accepted way of doing things, though, I'll adopt it. How about for pages which don't have a clear indicator that anything has changed? In my case I have a list of items and when you filter them you still have a list of items. – stimms Apr 03 '14 at 12:54
  • @stimms I don't know if it's an accepted way. I thought you meant wait function which relies on time rather than events. – Jakub Kania Apr 03 '14 at 12:57