PhantomJS et en cliquant sur un bouton de formulaire

J'ai un formulaire HTML très simple que je tente de tester avec différents types de données. J'ai écrit un prototype de preuve de concept dans MS Access / VBA à l'aide de l'objet IE. Cela a bien fonctionné, mais le produit d'essai fini doit utiliser PhantomJS. J'ai l'interfaçage de la page pour fonctionner et le formulaire est très peuplé. Là où je suis bloqué, le bouton soumettre est lancé. J'ai parcouru SO et essayé toutes les suggestions et rien ne fonctionne. J'utilise PhantomJS 1.9.7 et j'utilise des scripts de test JavaScript.

J'ai essayé diverses techniques de JavaScript pour déclencher le bouton de soumission. Pour satisfaire la foule "Just use JQuery", j'ai essayé cela aussi. Rien ne fonctionne. Lorsque je rends le formulaire à la fin du script de test, je vois le formulaire rempli de données attendant patiemment que le bouton <search> soit cliqué.

Voici un résumé de ce que j'ai essayé:

  1. document.getElementById('btnSearch').click();
  2. $("btnSearch").click();
  3. var el = document.getElementById('btnSearch'); // Get search button object
    $(el).click();
  4. document.getElementById('Form1').submit();
  5. Essayé de créer un événement de clic et de le tirer de l'objet de bouton (dans le code ci-dessous)
  6. Essayé de créer un événement de clic et de le tirer de l'objet du corps avec les coordonnées d'un point à l'intérieur du bouton en question

Voici le formulaire: (Et s'il vous plaît, pas de commentaires / débats sur le manque de CSS, l'utilisation de tables, etc. Je n'ai aucun mot ou influence sur les personnes qui ont créé le site.)

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <HTML> <HEAD> <title>Da Site</title> </HEAD> <body> <form name="Form1" method="post" action="Default.aspx" id="Form1"> <TABLE id="Table2" cellSpacing="2" cellPadding="1" border="0"> <TR> <TD>Street Address:</TD> <TD><input name="Address" type="text" maxlength="100" id="Address" /></TD> </TR> <TR> <TD>City:</TD> <TD><input name="City" type="text" maxlength="100" id="City" style="width:232px;"/></TD> </TR> <TR> <TD>State:</TD> <TD><select name="State" id="State"> <option value=""></option> <option value="AL">AL - Alabama</option> <option value="AK">AK - Alaska</option> [The rest of the other states] <option value="WI">WI - Wisconsin</option> <option value="WY">WY - Wyoming</option> <option value="PR">PR - Puerto Rico</option> </select> </TD> </TR> <TR> <TD>Zip Code:</TD> <TD><input name="ZipCode" type="text" maxlength="5" id="ZipCode" /></TD> </TR> <tr> <td><input type="submit" name="btnSearch" value="Search" id="btnSearch" /> <input type="submit" name="btnReset" value="Reset" id="btnReset" /> </td> </tr> </TABLE> </form> </body> </HTML> 

Voici le JavaScript pour générer le formulaire:

 var maxtimeOutMillis = 3000; var start; var finish; var page = require('webpage').create(); // Route "console.log()" calls from within the Page context to the main Phantom context (ie current "this") page.onConsoleMessage = function(msg) { console.log(msg); }; page.open('http://www.MadeUpURL.com/', function(status) { page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() { if (status !== 'success') { console.log('Unable to access network'); } else { page.render('before.png'); // Renders the blank form page.evaluate( function () { // page.render('Sample.png'); document.getElementById('Address').value = '123 Somewhere Drive'; document.getElementById('City').value = 'Somewhere'; document.getElementById('State').selectedIndex = 36; document.getElementById('ZipCode').value = '12345'; // I've done a page.render() here and it shows the form fully and correctly populated // Now let's submit the form... var el = document.getElementById('btnSearch'); // Get the "search" button object // Tried the usual suspects document.getElementById('btnSearch').click(); $("btnSearch").click(); $(el).click(); document.getElementById('Form1').submit(); // Tried creating a click event and firing it from the button object var ev = document.createEvent("MouseEvent"); ev.initMouseEvent("click", true /* bubble */, true /* cancelable */, window, null, 0, 0, 0, 0, /* coordinates */ false, false, false, false, /* modifier keys */ 0 /*left click*/, null); el.dispatchEvent(ev); // Tried calculating the location of the button itself (which works) and fire the click event from the <Body> object var obj = document.getElementById('btnSearch'); var x = obj.offsetLeft; var y = obj.offsetTop; while (obj.offsetParent) { x = x + obj.offsetParent.offsetLeft; y = y + obj.offsetParent.offsetTop; if (obj == document.getElementsByTagName("body")[0]) { break; } else { obj = obj.offsetParent; } } x = x + 5; // Tried with and without this +5 delta y = y + 5; // Tried with and without this +5 delta console.log('X = ' + x); console.log('Y = ' + y); var ev = document.createEvent("MouseEvent"); ev.initMouseEvent("click", true /* bubble */, true /* cancelable */, window, null, 0, 0, x, y, /* coordinates */ false, false, false, false, /* modifier keys */ 0 /*left click*/, null); document.body.dispatchEvent(ev); }); start = new Date().getTime(); finish = new Date().getTime(); console.log('Time before: ' + start); // Check to see if results are defined (or times out) while ( (finish - start < maxtimeOutMillis) && !( page.evaluate( function() {return document.getElementById('TheAnswer');}))) { finish = new Date().getTime(); } console.log('Time after: ' + finish); if ( page.evaluate( function() {return document.getElementById('TheAnswer');})) { console.log(page.evaluate( function() {return document.getElementById('TheAnswer').textContent;})); } else { console.log('Element not defined'); } } page.render('after.png'); phantom.exit(); }); }); 

J'espère que c'est l'un de ces types de chose que vous avez oublié-a-virgule, mais je ne le vois pas. Toute aide sera la bienvenue!

Modifier # 1: Ajout de la sortie du script à titre de référence.

 C:\Temp\WebAutomation\PhantomJS\scripts>phantomjs interact.js X = 151 Y = 442 Time before: 1407875912197 [edit #2 - change before/after labels to match code] Time after: 1407875915197 Element not defined C:\Temp\WebAutomation\PhantomJS\scripts> 

D'accord. Je pense que je l'ai compris. J'ai dirigé PhantomJS et mon script sur un site Web où je pouvais surveiller les données sur le back-end. À ma grande surprise, le bouton a été cliqué. Je ne pouvais tout simplement pas voir les résultats.

Grâce à cette publication de Vinjay Boyapati , le problème semble avoir plus à voir avec les gestionnaires de page et le séquençage. Il semble que la meilleure façon de gérer les transitions de page dans PhantomJS consiste à lancer le cycle de la page (cliquer sur un bouton de soumission, un lien, etc.) et quitter cette fonction d'évaluation JS. Après avoir vérifié PhantomJS pour vous assurer que la page a été complètement chargée et stable, appelez une autre page. Évaluez et recherchez ce que vous attendiez à trouver lorsque le navigateur récupère les résultats de votre soumission. Voici le code que j'ai copié / modifié de la publication de Vinjay:

Modifier : Une chose à attirer l'attention particulière. Pour chaque page. Évalue () où jQuery est nécessaire, page.injectJs("jquery1-11-1min.js"); la page.injectJs("jquery1-11-1min.js"); ligne. Dans le cas contraire, j'aurais "$ is undefined" comme une erreur de page.

 var page = require('webpage').create(); var loadInProgress = false; var testindex = 0; // Route "console.log()" calls from within the Page context to the main Phantom context (ie current "this") page.onConsoleMessage = function(msg) { console.log(msg); }; page.onAlert = function(msg) { console.log('alert!!> ' + msg); }; page.onLoadStarted = function() { loadInProgress = true; console.log("load started"); }; page.onLoadFinished = function(status) { loadInProgress = false; if (status !== 'success') { console.log('Unable to access network'); phantom.exit(); } else { console.log("load finished"); } }; var steps = [ function() { page.open('http://www.MadeUpURL.com'); }, function() { page.injectJs("jquery1-11-1min.js"); page.evaluate(function() { document.getElementById('Address').value = '302 E Buchtel Avenue'; //University of Akron if you're wondering document.getElementById('City').value = 'Akron'; document.getElementById('State').selectedIndex = 36; document.getElementById('ZipCode').value = '44325'; console.log('JQ: ' + $().jquery); $('#btnSearch').click(); console.log('Clicked'); }); }, function() { console.log('Answers:'); page.injectJs("jquery1-11-1min.js"); page.render('AnswerPage.png'); page.evaluate(function() { console.log('The Answer: ' + document.getElementById('TheAnswer').innerHTML); $('#buttonOnAnswerPage').click(); // This isn't really necessary unless you need to navigate deeper console.log('Sub button clicked'); }); }, function() { console.log('More Answers:'); // This function is for navigating deeper than the first-level form submission page.render('MoreAnswersPage.png'); page.evaluate(function() { console.log('More Stuff: ' + document.body.innerHTML); }); }, function() { console.log('Exiting'); } ]; interval = setInterval(function() { if (!loadInProgress && typeof steps[testindex] == "function") { console.log("step " + (testindex + 1)); steps[testindex](); testindex++; } if (typeof steps[testindex] != "function") { console.log("test complete!"); phantom.exit(); } }, 50);