Есть ли способ начать с запроса 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
Это очень похоже на другие методы имитации и заглушки, используемые в автоматическом тестировании. Вы просто издеваетесь над точкой входа в веб-приложение.
Очевидно, что у этого подхода есть некоторые ограничения:
- данные не могут быть слишком большими (например, данные изображения)
- безопасность может быть проблемой, поэтому вы должны убедиться, что эти тестовые файлы не попадают на ваш рабочий сервер
- вам может понадобиться сделать точки входа с помощью чего-то вроде php вместо html, если вам нужно установить cookie-файлы до начала теста Selenium
- некоторые веб-приложения проверяют реферер, чтобы удостовериться, что кто-то не взломал приложение - в этом случае этот подход, вероятно, не сработает - вы можете ослабить эту проверку в среде разработчика, поэтому он позволяет ссылаться с доверенных хостов (не самостоятельно), но фактический хозяин теста)
Пожалуйста, прочитайте мою статью о качествах идеального теста
В настоящее время 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&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("Results = " + xmlhttp.responseText);} else { alert("Error!"+ xmlhttp.responseText); }}}; 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()