Есть ли способ начать с запроса POST с использованием Selenium?

Я пытаюсь запустить тест Selenium с помощью запроса POST к моему приложению.

Вместо простого open(/startpoint)

Я хотел бы сделать что-то вроде open(/startpoint, stuff=foo,stuff2=bar)

Есть ли способ сделать это?

Я спрашиваю об этом, потому что исходная страница, которая отправляет сообщения в эту начальную точку, зависит от внешних провайдеров, которые часто находятся в автономном режиме (среда разработки) и поэтому часто терпят неудачу слишком рано (и не являются предметом теста)


Я думаю, отправка данных как GET тоже будет работать. Я бы просто предпочел использовать метод POST.

8 ответов

Решение

Краткий ответ: Нет.

Но вы могли бы сделать это с небольшим количеством грязи. Если вы откроете тестовую страницу (с помощью GET), то оцените некоторый JavaScript-код на этой странице, и вы сможете повторить запрос POST. Посмотрите пост-запрос JavaScript как форму отправки, чтобы увидеть, как вы можете повторить POST-запрос в JavaScript.

Надеюсь это поможет.

Если вы используете Python selenium привязки, в настоящее время, есть расширение selenium - selenium-requests:

Расширяет классы Selenium WebDriver для включения функции request из библиотеки Requests, выполняя всю необходимую обработку файлов cookie и заголовков запросов.

Пример:

from seleniumrequests import Firefox

webdriver = Firefox()
response = webdriver.request('POST', 'url here', data={"param1": "value1"})
print(response)

я использовал driver.execute_script()чтобы вставить html-форму на страницу, а затем отправить ее. Это выглядит так:

              def post(path, params):
            driver.execute_script("""
            function post(path, params, method='post') {
                const form = document.createElement('form');
                form.method = method;
                form.action = path;
            
                for (const key in params) {
                    if (params.hasOwnProperty(key)) {
                    const hiddenField = document.createElement('input');
                    hiddenField.type = 'hidden';
                    hiddenField.name = key;
                    hiddenField.value = params[key];
            
                    form.appendChild(hiddenField);
                }
              }
            
              document.body.appendChild(form);
              form.submit();
            }
            
            post(arguments[1], arguments[0]);
            """, params, path)

        # example 
        post(path='/submit', params={'name': 'joe'})

Если хотите, вы можете просто добавить функцию в \selenium\webdriver\chrome\webdriver.pyа затем используйте его в своем коде с помощью driver.post()

Один очень практичный способ сделать это - создать фиктивную стартовую страницу для ваших тестов, которая представляет собой просто форму с POST, в которой есть одна кнопка "начать тест" и куча <input type="hidden"... элементы с соответствующими почтовыми данными.

Например, вы можете создать SeleniumTestStart.html страница с таким содержанием:

<body>
  <form action="/index.php" method="post">
    <input id="starttestbutton" type="submit" value="starttest"/>
    <input type="hidden" name="stageid" value="stage-you-need-your-test-to-start-at"/>
  </form>
</body>

В этом примере index.php - это место, где находится ваше обычное веб-приложение.

Код Selenium в начале ваших тестов будет включать:

open /SeleniumTestStart.html
clickAndWait starttestbutton

Это очень похоже на другие методы имитации и заглушки, используемые в автоматическом тестировании. Вы просто издеваетесь над точкой входа в веб-приложение.

Очевидно, что у этого подхода есть некоторые ограничения:

  1. данные не могут быть слишком большими (например, данные изображения)
  2. безопасность может быть проблемой, поэтому вы должны убедиться, что эти тестовые файлы не попадают на ваш рабочий сервер
  3. вам может понадобиться сделать точки входа с помощью чего-то вроде php вместо html, если вам нужно установить cookie-файлы до начала теста Selenium
  4. некоторые веб-приложения проверяют реферер, чтобы удостовериться, что кто-то не взломал приложение - в этом случае этот подход, вероятно, не сработает - вы можете ослабить эту проверку в среде разработчика, поэтому он позволяет ссылаться с доверенных хостов (не самостоятельно), но фактический хозяин теста)

Пожалуйста, прочитайте мою статью о качествах идеального теста

В настоящее время Selenium не предлагает API для этого, но есть несколько способов инициировать HTTP-запрос в вашем тесте. Это зависит только от того, на каком языке вы пишете.

Например, в Java это может выглядеть так:

// setup the request
String request = "startpoint?stuff1=foo&stuff2=bar";
URL url = new URL(request);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");

// get a response - maybe "success" or "true", XML or JSON etc.
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
StringBuffer response = new StringBuffer();
while ((line = bufferedReader.readLine()) != null) {
    response.append(line);
    response.append('\r');
}
bufferedReader.close();

// continue with test
if (response.toString().equals("expected response"){
    // do selenium
}

Selenium IDE позволяет запускать Javascript с помощью команды storeEval. Упомянутое выше решение отлично работает, если у вас есть тестовая страница (HTML, а не XML), и вам нужно выполнить только POST-запрос.

Если вам нужно сделать POST/PUT/DELETE или любой другой запрос, вам понадобится другой подход:

XMLHttpRequest!

Приведенный ниже пример был протестирован - все методы (POST/PUT/DELETE) работают нормально.

<!--variables-->
<tr>
    <td>store</td>
    <td>/your/target/script.php</td>
    <td>targetUrl</td>
</tr>
<tr>
    <td>store</td>
    <td>user=user1&amp;password</td>
    <td>requestParams</td>
</tr>
<tr>
    <td>store</td>
    <td>POST</td>
    <td>requestMethod</td>
</tr>
<!--scenario-->
<tr>
    <td>storeEval</td>
    <td>window.location.host</td>
    <td>host</td>
</tr>
<tr>
    <td>store</td>
    <td>http://${host}</td>
    <td>baseUrl</td>
</tr>
<tr>
    <td>store</td>
    <td>${baseUrl}${targetUrl}</td>
    <td>absoluteUrl</td>
</tr>
<tr>
    <td>store</td>
    <td>${absoluteUrl}?${requestParams}</td>
    <td>requestUrl</td>
</tr>
<tr>
    <td>storeEval</td>
    <td>var method=storedVars['requestMethod']; var url = storedVars['requestUrl']; loadXMLDoc(url, method); function loadXMLDoc(url, method) { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { if(xmlhttp.status==200) { alert(&quot;Results = &quot; + xmlhttp.responseText);} else { alert(&quot;Error!&quot;+ xmlhttp.responseText); }}};&nbsp;&nbsp;xmlhttp.open(method,url,true); xmlhttp.send(); }</td>
    <td></td>
</tr>

Разъяснение:

$ { requestParams } - параметры, которые вы хотите опубликовать (например, param1=value1¶m2=value3¶m1=value3), вы можете указать столько параметров, сколько вам нужно

$ { targetUrl } - путь к вашему сценарию (если ваша страница находится по адресу http://domain.com/application/update.php то targetUrl должен быть равен /application/update.php)

$ { requestMethod } - тип метода (в данном конкретном случае это должно быть "POST", но может быть "PUT" или "DELETE" или любой другой)

Ну, я согласен с ответом @Mishkin Berteig - Agile Coach. Использование формы - это быстрый способ использовать функции POST.

Во всяком случае, я вижу некоторые упоминания о JavaScript, но нет кода. У меня есть это для моих собственных нужд, которое включает в себя jquery для простого POST плюс другие.

В основном, используя driver.execute_script() Вы можете отправить любой javascript, включая запросы Ajax.

#/usr/local/env/python
# -*- coding: utf8 -*-
# proxy is used to inspect data involved on the request without so much code.
# using a basic http written in python. u can found it there: http://voorloopnul.com/blog/a-python-proxy-in-less-than-100-lines-of-code/

import selenium
from selenium import webdriver
import requests
from selenium.webdriver.common.proxy import Proxy, ProxyType

jquery = open("jquery.min.js", "r").read()
#print jquery

proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "127.0.0.1:3128"
proxy.socks_proxy = "127.0.0.1:3128"
proxy.ssl_proxy = "127.0.0.1:3128"

capabilities = webdriver.DesiredCapabilities.PHANTOMJS
proxy.add_to_capabilities(capabilities)

driver = webdriver.PhantomJS(desired_capabilities=capabilities)

driver.get("http://httpbin.org")
driver.execute_script(jquery) # ensure we have jquery

ajax_query = '''
            $.post( "post", {
                "a" : "%s",
                "b" : "%s"
            });
            ''' % (1,2)

ajax_query = ajax_query.replace(" ", "").replace("\n", "")
print ajax_query

result = driver.execute_script("return " + ajax_query)
#print result

#print driver.page_source

driver.close()

# this retuns that from the proxy, and is OK
'''
POST http://httpbin.org/post HTTP/1.1
Accept: */*
Referer: http://httpbin.org/
Origin: http://httpbin.org
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.0.0 Safari/538.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 7
Cookie: _ga=GAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; _gat=1
Connection: Keep-Alive
Accept-Encoding: gzip, deflate
Accept-Language: es-ES,en,*
Host: httpbin.org


None
a=1&b=2  <<---- that is OK, is the data contained into the POST
None
'''
      from selenium import webdriver

driver = webdriver.Firefox()
driver.implicitly_wait(12)
driver.set_page_load_timeout(10)

def _post_selenium(self, url: str, data: dict):
    input_template = '{k} <input type="text" name="{k}" id="{k}" value="{v}"><BR>\n'
    inputs = ""
    if data:
        for k, v in data.items():
            inputs += input_template.format(k=k, v=v)
    html = f'<html><body>\n<form action="{url}" method="post" id="formid">\n{inputs}<input type="submit" id="inputbox">\n</form></body></html>'

    html_file = os.path.join(os.getcwd(), 'temp.html')
    with open(html_file, "w") as text_file:
        text_file.write(html)

    driver.get(f"file://{html_file}")
    driver.find_element_by_id('inputbox').click()

_post_selenium("post.to.my.site.url", {"field1": "val1"})

driver.close()
Другие вопросы по тегам