简体   繁体   中英

How to trigger Ajax Request for filling a Form out and wait until DOM changes?

I am going to fill out a Form using JQuery through PhantomJS.

I have following script for doing that:

var page = require('webpage').create();

page.open('http://demo.opencart.com/index.php?route=account/register', function() {
    fillTheForm();
    phantom.exit();
});

function fillTheForm () {

    page.evaluate(function() {

        var selectTags = new Array();
        selectTags = document.getElementsByTagName('select');
        $(selectTags[0]).val("38");
        $(selectTags[0]).trigger('change');

        $(selectTags[1]).val('610');
    });         
    page.render('form.png');
};

after running this script, I got following message inside the console!

Alert, JavaScript error

Also, the picture that I have, after trying to fill the Form out, tells me that the existing values for the second Select box have not changed yet and then PhantomJS could not assign the value to the second field.

Can someone please help me to solve this problem? How can I fill out this two fields using JQuery and PhantomJS?

This is the chained selects problem. The second one is dependent on the first one and is populated via AJAX. This means that it is asynchronous. You have to wait before you can set the second value. In PhantomJS this is also problematic, because you have two contexts (page context and phantom context) that have do be "synchronized".

For example you can use

function fillTheForm () {
    page.evaluate(function() {
        var selectTags = document.getElementsByTagName('select');
        $(selectTags[0]).val("38");
        $(selectTags[0]).trigger('change');
    });
    setTimeout(function(){
        page.evaluate(function() {
            var selectTags = document.getElementsByTagName('select');
            $(selectTags[1]).val('610');
        });
        page.render('form.png');
        phantom.exit(); // this has to be inside, because everything is asynchronous now
    }, 3000); // assuming 3 seconds are enough time for the request
};

A better and more robust way would be to use waitFor from the examples , because it is finished as soon as the data is available. Here I have some indicators when the second select is reloaded:

var page = require('webpage').create();

page.open('http://demo.opencart.com/index.php?route=account/register', function() {
    fillTheForm(function(){
        page.render('form.png');
        phantom.exit();
    });
});

function fillTheForm(done) {
    page.evaluate(function() {
        var selectTags = document.getElementsByTagName('select');

        // custom indicators, perhaps something more elaborate is needed for general selects
        // in this case it is ok
        window._chainedSelectChildrenLength = selectTags[1].children.length;
        window._chainedSelectFirstChildText = selectTags[1].children[0].innerText;

        $(selectTags[0]).val("38");
        $(selectTags[0]).trigger('change');
    });
    waitFor(function testFx(){
        return page.evaluate(function() {
            var selectTags = document.getElementsByTagName('select');
            // use indicators
            return window._chainedSelectChildrenLength !== selectTags[1].children.length ||
                window._chainedSelectFirstChildText !== selectTags[1].children[0].innerText;
        });
    }, function onReady(){
        page.evaluate(function(){
            // continue
            var selectTags = document.getElementsByTagName('select');
            $(selectTags[1]).val('610');
        });
        done();
    }, 5000); // 3 seconds is the default
};

function waitFor(testFx, onReady, timeOutMillis) {
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
        start = new Date().getTime(),
        condition = false,
        interval = setInterval(function() {
            if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
                // If not time-out yet and condition not yet fulfilled
                condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
            } else {
                if(!condition) {
                    // If condition still not fulfilled (timeout but condition is 'false')
                    console.log("'waitFor()' timeout");
                    phantom.exit(1);
                } else {
                    // Condition fulfilled (timeout and/or condition is 'true')
                    console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
                    typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 250); //< repeat check every 250ms
};

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