5

Here my problem : I'm in a specific case where I try to set the option of a select dropdown list. I usually use this.mouse.up() + this.mouse.down() but I can't in this case because this behavior doesn't work on the website with webkit (you can compare the two with google chrome and Firefox).

Here the url : I want to set the field 'ANNEE' to a year, 2008 in my example

My code : (my function changes the HTML and launches the change() event)

//custom function
casper.fillSelect = function(selectSelector, optionText){
    this.evaluate(function(sel,setByText) {
        if ("createEvent" in document) {
            var evt = document.createEvent("HTMLEvents")
                ,x = document.querySelectorAll(sel + ' > option')
                ,l = x.length
                ;
                evt.initEvent("change", false, true);

            for (i=0; i<l; i++){
                if(x[i].textContent.indexOf(setByText) !== -1){
                    console.log(x[i]);
                    console.log(x[i].getAttribute('value'));
                    x[i].setAttribute('selected', true);
                    x[i].parentNode.dispatchEvent(evt);
                }
            }
        }
        else {console.log("error with fillSelect");}
    },selectSelector, optionText);
};

//event
casper.test.on('fail', function(failure) {
    casper.capture('fail.png');
});

/*************************************** Tests *****************************************************/
casper.test.begin('\n********* Compare : ***********', function (test) {
    "use strict";
    casper.start()
    .thenOpen("http://www.linternaute.com/voyage/climat/paris/ville-75056",function(){
        casper.fillSelect('fieldset.fcNeutre > div.odSelect:nth-of-type(2) > select', '2008');
    })
    .waitForUrl(/2008/, function(){
        this.capture('fail2.png');
        this.test.assertSelectorHasText("h2", "maximales");
        this.test.assertSelectorHasText("h2", "minimales");
        this.test.assertSelectorHasText("h2", "Paris");
        this.test.assertSelectorHasText("h2", "Le soleil");
        this.test.assertSelectorHasText("h2", "La pluie");
        this.test.assertExists("tspan");
        this.test.assertExists("div.marB20");
        this.test.assertNotEquals(this.fetchText("div.marB20 > table > thead > tr > th"), "", "Table first data not empty");
    })
    .run(function() {
            this.test.comment('--- Done ---\n');
            test.done();
    });
});

And the equivalent to my casper custom function, you can execute it in the browser :

var fillSelect = function(sel,setByText) {
    if ("createEvent" in document) {
        var evt = document.createEvent("HTMLEvents")
            ,x = document.querySelectorAll(sel + ' > option')
            ,l = x.length
            ;
            evt.initEvent("change", false, true);

        for (i=0; i<l; i++){
            if(x[i].textContent.indexOf(setByText) !== -1){
                //console.log(x[i]);
                //console.log(x[i].getAttribute('value'));
                x[i].setAttribute('selected', true);
                x[i].parentNode.dispatchEvent(evt);
            }
        }
    }
    else {console.log("error with fillSelect");}
};

fillSelect('fieldset.fcNeutre > div.odSelect:nth-of-type(2) > select', '2008');

So it works in FF, Google Chrome, with slimerJS, but not with PhantomJS ... help please, if you have another idea to just select one option in this 'ANNEE' field, with casper+phantom, I take !

Could it be a problem of browser compatibility?

It's strange because in the same website, sometimes it works with other 'select', identical to this one ...

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Fanch
  • 3,274
  • 3
  • 20
  • 51

2 Answers2

3

So my final solution (thanks to sudipto)

casper.fillSelect = function(selectSelector, optionText){
    this.evaluate(function(sel, val) {
        jQuery(sel).find("option:contains('" + val + "')").attr('selected', true).change();  
    }, selectSelector, optionText);
};

casper.fillSelect('fieldset.fcNeutre > div.odSelect:nth-of-type(2) > select', '2008');

Raptor
  • 53,206
  • 45
  • 230
  • 366
Fanch
  • 3,274
  • 3
  • 20
  • 51
  • You can also do `...find('option[value="' + val + '"]')` to search the option value instead of the option text. – kumar303 Jan 23 '15 at 17:13
  • Yep, it depends of your preference ! – Fanch Jan 24 '15 at 16:08
  • 1
    I think @kumar303 's comment is not a matter of personal preferences...it is safer than just looking for text "anywhere". Imagine if you have an option that, by coincidence, doesn't have the value you're looking for, but its label matches that value you look for. You option will fail while the suggested one won't. Another comment, I liked your first approach better 'cause this one, even though it works, relies on JQuery, which might not be available everywhere. – Clint Eastwood Feb 11 '15 at 14:47
  • Yes, true. Was the case in **my** case. – Fanch Feb 11 '15 at 17:28
2

Since the page already has jQuery in it, I wrote this code and the capture as well as currentUrl shows the change happening. Jquery is able to raise the event correctly. I guess.

I hope you can extract the necessary code from this:

casper.on("load.finished", function (status) {
    if (status !== "success") {
        console.log('Failed to load page.');
    }
    else {

        var thisurl = casper.getCurrentUrl();
        window.count = (window.count || 0)+1;
        casper.capture('loaded'+window.count+'.png');

        if (window.count ==1) {
            casper.evaluate(function(sel, val){

                jQuery(sel).find("option:contains('"+val+"')").attr('selected', true);  
                jQuery(sel).change();

            }, 'fieldset.fcNeutre > div.odSelect:nth-of-type(2) > select', 2008);
        }

        console.log('Page loaded.' + thisurl);
        //casper.wait(2000, function(){
    }
});

Best of luck.

sudipto
  • 2,472
  • 1
  • 17
  • 21