Making a POST request in Selenium without filling a form?
forms, post, request, selenium, testing
Solution
With selenium you can execute arbitrary Javascript including programmatically submit a form.
Simplest JS execution with Selenium Java:
if (driver instanceof JavascriptExecutor) {
System.out.println(((JavascriptExecutor) driver).executeScript("prompt('enter text...');"));
}
and with Javascript you can create a POST request, set the required parameters and HTTP headers, and submit it.
// Javascript example of a POST request
var xhr = new XMLHttpRequest();
// setting 3rd arg to false forces *synchronous* mode
xhr.open('POST', 'http://httpbin.org/post', false);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send('login=test&password=test');
alert(xhr.response);
In modern bleeding edge browsers you can also use `fetch()`.
If you need to pass over to selenium the response text then instead of `alert(this.responseText)` use `return this.responseText` or `return this.response` and assign to a variable the result of `execute_script` (or `execute_async_script`) (if using python). For java that will be `executeScript()` or `executeAsyncScript()` correspondingly.
Here is a full example for python:
from selenium import webdriver
driver = webdriver.Chrome()
js = '''var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://httpbin.org/post', false);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send('login=test&password=test');
return xhr.response;'''
result = driver.execute_script(js);
`result` will contain the return value of your JavaScript provided that the js code is synchronous. Setting `false` as the third argument to `xhr.open(..)` forces the request to be synchronous. Setting the 3rd arg to `true` or omitting it will make the request asynchronous.
❗️ If you are calling asynchronous js code then make sure that instead of `execute_script` you use `execute_async_script` or otherwise the call won't return anything!
NOTE: If you need to pass string arguments to the javascript make sure you always escape them using `json.dumps(myString)` or otherwise your js will break when the string contains single or double quotes or other tricky characters.
Problem
I have an application A that should handle a form submit made with POST method. The actual form, that initiates the request, is in totally separate application B. I am testing application A using Selenium, and I like to write a test case for form submit handling. How to do this? Can this be done in Selenium at all? Application A does not have a form that can initiate this request. Note, that the request must use POST, otherwise I could just use WebDriver.get(url) method.