Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to open a new tab in CasperJS

I am using CasperJS testing framework to make some test suite since almost a month now, but I am facing a problem in one of them.

Here is what I want to do: I am browsing a url (page1) and I have to make another action from an another url (simulate a new tab like we have on our graphics browser) without quitting the first one (page1). The action from the second url is going to change my first one. Hope it's clear enough :)

So for now when I reach the step to observe that on my first url I open the second one by doing a thenOpen(), so it's making a new navigation step and I am losing the current session and I cannot come back on it. I try many way such as using the history, reopen the page, using the event from CasperJS and also I try with PhantomJS but without success.

Here is some pseudo code to make it clearer:

casper.test.begin("A random test suite", 0, function testSuite(test) {
    casper.start(url1, function () {
        casper.then(function() {
            // do some action on the first url
        });

        casper.then(function () {
            // open url2 and do some action in a new tab to not lose the session of url1
        });

        casper.then(function () {
            // check url1 (who should be still open)
        });
    });

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

I really would like to use CasperJS to do that but I start to think it is not possible, and I am starting to look in different solution such as this post: CasperJS, parallel browsing WITH the testing framework. But I have never use node.js before so if it's the only way please show me some example.

like image 579
TuZ Avatar asked Jul 22 '14 06:07

TuZ


1 Answers

Generally, it's not possible because a casper script runs inside only one phantomjs runtime. In your case it seems possible.

Note: Because this relies on a second casper instance, this cannot be used in a casper test environment.

You can create a new casper instance (casper2) inside one step of the outer casper instance (casper1). You then have to instruct casper1 to wait for completion of the casper2 instance, since casper is asynchronous in nature. Keep in mind that this is exactly like a new tab, so the instances will share the cache, cookies and storage.

Here is an sample script:

var casper1 = require('casper').create();
var casper2done = false;

casper1.start("http://www.example.com").then(function(){
    casper1.capture("casper1_1.png");
    var casper2 = require('casper').create();
    casper2.start("http://stackoverflow.com/contact").then(function(){
        casper1.echo(casper2.getCurrentUrl(), casper2.getTitle());
        casper2.capture("casper2.png");
    }).run(function(){
        this.echo("DONE 2");
        casper2done = true;
    });
}).waitFor(function check(){
    return casper2done;
}).then(function(){
    casper1.echo(casper1.getCurrentUrl(), casper1.getTitle()); // Comment to fix answer (min 6 chars)
    casper1.capture("casper1_2.png");
}).run(function(){
    this.echo("DONE");
    this.exit();
});

Here I use the promise chaining/builder pattern. You can even make your own function to hide the complexity and make it repeatedly usable:

var casper = require('casper').create();

// IIFE to hide casper2done variable
(function(casper){
    var casper2done = false;
    casper.newTab = function(url, then, timeout){
        if (typeof url !== "string" || typeof then !== "function") {
            throw "URL or then callback are missing";
        }
        this.then(function(){
            var casper2 = require('casper').create();
            casper2.start(url).then(then).run(function(){
                casper2done = true;
            });
        }).waitFor(function check(){
            return casper2done;
        }, null, null, timeout).then(function(){
            casper2done = false;
        });
        return this;
    };
})(casper);

casper.start("http://www.example.com").newTab("http://stackoverflow.com/contact", function(){
    // this is casper2
    this.echo(this.getCurrentUrl(), this.getTitle());
    this.capture("casper2_1.png");
    this.thenClick("a#nav-askquestion");
    this.then(function(){
        this.echo(this.getCurrentUrl(), this.getTitle());
        this.capture("casper2_2.png");
    });
}, 15000).then(function(){
    // this is casper
    this.echo(casper.getCurrentUrl(), casper.getTitle());
    this.capture("casper1.png");
}).run(function(){
    this.echo("DONE");
    this.exit();
});

You can use multiple steps in your child casper instance, but don't forget to specify a good timeout.

like image 70
Artjom B. Avatar answered Nov 07 '22 18:11

Artjom B.