【问题标题】:PhantomJS and clicking a form buttonPhantomJS 并单击表单按钮
【发布时间】:2014-10-06 22:32:54
【问题描述】:

我有一个非常简单的 HTML 表单,我正在尝试使用各种数据进行测试。我使用 IE 对象在 MS Access/VBA 中编写了一个原型概念验证。它运行良好,但完成的测试产品必须使用 PhantomJS。我已经让页面接口工作并且表单填充得很好。我被卡住的地方是让提交按钮触发。我已经梳理了 S.O.并尝试了所有建议,但没有任何效果。我正在使用 PhantomJS 1.9.7 并使用直接的 JavaScript 测试脚本。

我尝试了各种 JavaScript 技术来触发提交按钮。为了满足“只使用 JQuery”的人群,我也尝试过。没有任何工作。当我在测试脚本结束时呈现表单时,我看到表单中填充了数据,耐心等待点击 按钮。

以下是我尝试过的总结:

  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. 尝试创建一个点击事件并从按钮对象触发它(在下面的代码中)
  6. 尝试创建一个点击事件并从 body 对象触发它,并使用相关按钮内的某个点的坐标

表格如下: (请不要就缺乏 CSS、表格的使用等进行 cmets/辩论。我对创建该网站的人没有发言权或影响力。)

<!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>

这是驱动表单的 JavaScript:

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 (i.e. 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();

  });

});

我希望这是一种你忘记分号的东西,但我就是没看到。任何帮助将不胜感激!

编辑#1:添加脚本输出以供参考。

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>

【问题讨论】:

  • 我知道我知道,不是你的但是:validator.w3.org/check 在 xhtml 中严格说 element X undefined: upper-case tags in XHTML (in XHTML attributes and elements must be all lower-case)
  • 如果您手动提交,document.getElementById('TheAnswer'); 是否存在于(下一页)页面上?
  • @Artjom:很好——我将“到达这里”改为“之前”和“这里”改为“之后”。我会进行适当的编辑...
  • @Birdspider:当你说“手动提交”时,你是什么意思?如果我在适当的浏览器中加载网页并输入地址并单击“搜索”按钮,则该页面会加载各种数据,包括“TheAnswer”。这就是我在这里的坚持。我无法让 PhantomJS 通过单击按钮或直接 form.submit() 提交表单
  • 试试这个:在文件中方便的地方添加debugger;。然后开始phantomjs --remote-debugger-port=8889 &lt;file&gt;.js。在 localhost:8889 上打开 chrome - 单击链接,转到控制台并执行 __run() - 您现在应该能够逐步执行脚本 - 以 debugger 开始一行;

标签: javascript jquery forms automated-tests phantomjs


【解决方案1】:

好的。我想我想通了。我将 PhantomJS 和我的脚本定向到一个网站,在那里我可以监控后端的数据。令我惊讶的是,按钮 被点击了。我只是看不到结果。

感谢this post from Vinjay Boyapati,这个问题似乎更多地与页面处理程序和排序有关。似乎在 PhantomJS 中处理页面转换的最佳方法是启动页面循环(单击提交按钮、链接等)并退出 JS 评估功能。在检查 PhantomJS 以确保页面已完全加载且稳定后,调用另一个 page.evaluate 并在浏览器取回提交结果时查找您期望找到的任何内容。这是我从 Vinjay 的帖子中复制/修改的代码:

编辑:需要特别注意的一件事。对于需要 jQuery 的每个 page.Evaluates(),我添加了 page.injectJs("jquery1-11-1min.js"); 行。否则我会得到“$ is undefined”作为页面错误。

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 (i.e. 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);

【讨论】:

  • 谢谢。我有一些错误。经过一番搜索,我发现最好将延迟设置为 500 而不是 50。这对我来说只是一个非常快速和肮脏的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 2012-10-16
相关资源
最近更新 更多