How to check image requests for 404 using Selenium WebDriver? - selenium

What is the most convenient way using Selenium WebDriver to check if an URL GET returns successfully (HTTP 200)?
In this particular case I'm most interested in verifying that no images of the current page are broken.

Try this:
List<WebElement> allImages = driver.findElements(By.tagName("img"));
for (WebElement image : allImages) {
boolean loaded = ((JavaScriptExecutor) driver).executeScript(
"return arguments[0].complete", image);
if (!loaded) {
// Your error handling here.
}
}

You could use the getEval command to verify the value returned from the following JavaScript for each image on the page.
#Test
public void checkForBrokenImages() {
selenium.open("http://www.example.com/");
int imageCount = selenium.getXpathCount("//img").intValue();
for (int i = 0; i < imageCount; i++) {
String currentImage = "this.browserbot.getUserWindow().document.images[" + i + "]";
assertEquals(selenium.getEval("(!" + currentImage + ".complete) ? false : !(typeof " + currentImage + ".naturalWidth != \"undefined\" && " + currentImage + ".naturalWidth == 0);"), "true", "Broken image: " + selenium.getEval(currentImage + ".src"));
}
}
Updated:
Added tested TestNG/Java example.

I don't think that first response will work. When I src a misnamed image, it throws a 404 error as expected. However, when I check the javascript in firebug, that (broken) image has .complete set to true. So, it was a completed 404, but still a broken image.
The second response seems to be more accurate in that it checks that it's complete and then checks that there is some width to the image.
I made a python version of the second response that works for me. Could be cleaned up a bit, but hopefully it will help.
def checkForBrokenImages(self):
sel = self.selenium
imgCount = int(sel.get_xpath_count("//img"))
for i in range(0,imgCount):
isComplete = sel.get_eval("selenium.browserbot.getCurrentWindow().document.images[" + str(i) + "].complete")
self.assertTrue(isComplete, "Bad Img (!complete): "+sel.get_eval("selenium.browserbot.getCurrentWindow().document.images[" + str(i) + "].src"))
typeOf = sel.get_eval("typeof selenium.browserbot.getCurrentWindow().document.images[" + str(i) + "].naturalWidth")
self.assertTrue(typeOf != 'undefined', "Bad Img (w=undef): "+sel.get_eval("selenium.browserbot.getCurrentWindow().document.images[" + str(i) + "].src"))
natWidth = int(sel.get_eval("selenium.browserbot.getCurrentWindow().document.images[" + str(i) + "].naturalWidth"))
self.assertTrue(natWidth > 0, "Bad Img (w=0): "+sel.get_eval("selenium.browserbot.getCurrentWindow().document.images[" + str(i) + "].src"))

Instead of traversing in Java, it may be faster to call javascript only once for all images.
boolean allImgLoaded = (Boolean)((JavascriptExecutor) driver).executeScript(
"return Array.prototype.slice.call(document.images).every("
+ "function (img) {return img.complete && img.naturalWidth > 0;});");

One of the alternative solutions is analyzing web server logs after test executing. This approach allows to catch not only missed images, but css, scripts and other resources.
Description of how to do it is here.

Funda for Checking 404:
Basically 404s can be checked via HTTP Response of the URL.
Step 1: Import the Library for HTTPTestAPI
Step 2: Create the HTTPRequest.
String URL="www.abc.com";
HTTPRequest request = new HTTPRequest(URL);
//Get the response code of the URL
int response_code = request.getResponseCode();
//Check for 404:
if(response_code == 404)
FAIL -- THE URL is leading to 404.
else
PASS

Related

How to get the response body from network tab using Selenium 4 (devTools)

I am using devTools in selenium 4 to retrieve the responses from the network tab.
While I am getting the url, response code, headers etc,
I could not find a way to retrieve the actual response body. (My intention is to validate the key value pairs in the response.)
Any help is much appreciated.
Below is a snippet from my code.
devTools.addListener(Network.responseReceived(),
response -> {
Response res= response.getResponse();
System.out.println("URL - " + res.getUrl());
System.out.println("Status - " + res.getStatus());
System.out.println("Headers - " + res.getHeaders());
System.out.println("Header text - " + res.getHeadersText());
});
devTools = ((ChromeDriver) driver).getDevTools();
devTools.createSession();
devTools.send(Network.clearBrowserCache());
devTools.send(Network.setCacheDisabled(true));
final RequestId[] requestIds = new RequestId[1];
devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.of(100000000)));
devTools.addListener(Network.responseReceived(), responseReceived -> {
requestIds[0] = responseReceived.getRequestId();
String url = responseReceived.getResponse().getUrl();
int status = responseReceived.getResponse().getStatus();
String type = responseReceived.getType().toJson();
String headers = responseReceived.getResponse().getHeaders().toString();
String responseBody = devTools.send(Network.getResponseBody(requestIds[0])).getBody();

Multipart form upload of binary file using casperjs outside of state machine (can't use fill)

UPDATE 1: I've created a GIST with actual running code in a test jig to show exactly what I'm running up against. I've included working bot tokens (to a throw-away bot) and access to a telegram chat that the bot is already in, in case anyone wants to take a quick peek. It's
https://gist.github.com/pleasantone/59efe5f9d7f0bf1259afa0c1ae5a05fe
UPDATE 2: I've looked at the following articles for answers already (and a ton more):
https://github.com/francois2metz/html5-formdata/blob/master/formdata.js
PhantomJS - Upload a file without submitting a form
https://groups.google.com/forum/#!topic/casperjs/CHq3ZndjV0k
How to instantiate a File object in JavaScript?
How to create a File object from binary data in JavaScript
I've got a program written in casperjs (phantomjs) that successfully sends messages to Telegram via the BOT API, but I'm pulling my hair out trying to figure out how to send up a photo.
I can access my photo either as a file, off the local filesystem, or I've already got it as a base64 encoded string (it's a casper screen capture).
I know my photo is good, because I can post it via CURL using:
curl -X POST "https://api.telegram.org/bot<token>/sendPhoto" -F chat_id=<id> -F photo=#/tmp/photo.png
I know my code for connecting to the bot api from within capserjs is working, as I can do a sendMessage, just not a sendPhoto.
function sendMultipartResponse(url, params) {
var boundary = '-------------------' + Math.floor(Math.random() * Math.pow(10, 8));
var content = [];
for (var index in params) {
content.push('--' + boundary + '\r\n');
var mimeHeader = 'Content-Disposition: form-data; name="' + index + '";';
if (params[index].filename)
mimeHeader += ' filename="' + params[index].filename + '";';
content.push(mimeHeader + '\r\n');
if (params[index].type)
content.push('Content-Type: ' + params[index].type + '\r\n');
var data = params[index].content || params[index];
// if (data.length !== undefined)
// content.push('Content-Length: ' + data.length + '\r\n');
content.push('' + '\r\n');
content.push(data + '\r\n');
};
content.push('--' + boundary + '--' + '\r\n');
utils.dump(content);
var xhr = new XMLHttpRequest();
xhr.open("POST", url, false);
if (true) {
/*
* Heck, try making the whole thing a Blob to avoid string conversions
*/
body = new Blob(content, {type: "multipart/form-data; boundary=" + boundary});
utils.dump(body);
} else {
/*
* this didn't work either, but both work perfectly for sendMessage
*/
body = content.join('');
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
// xhr.setRequestHeader("Content-Length", body.length);
}
xhr.send(body);
casper.log(xhr.responseText, 'error');
};
Again, this is in a CASPERJS environment, not a nodejs environment, so I don't have things like fs.createReadableStream or the File() constructor.

Fiddler script to automatically save response body

I need help writing a script for fiddler. What I need is to automatically save a certain response body every time it comes up in the session window.
I have tried to follow the instructions in this post Fiddler Script - SaveResponseBody() but I just get an error when I try and save CustomRules.js. (I could be inserting in wrong or in the wrong place)
I am new to fiddler and scripts so any help here would be greatly appreciated.
I have tried adding this:
static function OnBeforeResponse(oSession: Session) {
if(oSession.url.EndsWith(".png")) {
oSession.SaveResponseBody(); //Actual content of OnBeforeResponse function.
}
}
and then adding this:
if ((oSession.responseCode == 200) &&
oSession.oResponse.headers.ExistsAndContains("Content-Type", "image/png")) {
SaveResponseBody("C:\\temp\\" + oSession.SuggestedFilename);
}
to the CustomRules.js script.
SaveResponseBody is a method on the oSession object.
oSession.SaveResponseBody("C:\\temp\\" + oSession.SuggestedFilename);
Be sure to add your code within OnBeforeResponse(oSession: Session) { ... } function
The following code will save the request and response body of any url that contains "procedimentoservice" and a response code that differs from OK (200).
if (oSession.PathAndQuery.ToLower().Contains("procedimentoservice"))
{
if(oSession.responseCode != 200)
{
var directory2 = "C:\\log\\NEXT\\";
var filename2 = oSession.oRequest.headers['SOAPAction'].ToString().Replace('"','') + "_" + Guid.NewGuid();
var path2: String = System.IO.Path.Combine(directory2, filename2);
oSession.SaveRequestBody(path2 + "_request.txt");
oSession.SaveResponseBody(path2 + "_response.txt");
}
}
File names will be in the following format:
c:\log\NEXT\CriarEvento_fa15709e-b2a8-402d-a623-e4f01e6e8ae1_request.txt
c:\log\NEXT\CriarEvento_fa15709e-b2a8-402d-a623-e4f01e6e8ae1_response.txt
c:\log\NEXT\CriarEvento_ff650cf8-8fe6-47a2-8552-a4d8bce246f3_request.txt
c:\log\NEXT\CriarEvento_ff650cf8-8fe6-47a2-8552-a4d8bce246f3_response.txt

SharePoint 2010 Wiki Template Script Issue

I'm looking for a way to give my SharePoint users a way to create new wiki pages from an existing template. In the process of researching I found a great walkthrough that seems to fit the need (http://www.mssharepointtips.com/tip.asp?id=1072&page=2), but I'm having trouble getting it to work. The problem seems to lie in the assignment of a path to PATHTOWIKI-- if I use "/Weekly Update Wiki", the script returns an error of "There is no Web named '/Weekly Update Wiki'." If I use "Weekly Update Wiki" without the forward slash, I instead get an error of "There is no Web named '/sites/[parentSite]/[childSite]/Weekly Update Wiki/Weekly Update Wiki'."
Any ideas about what I'm not understanding here?
function myCreateProject() {
// Configure these for your environment
// include no slashes in paths
var PATHTOWIKI = "Weekly Update Wiki";
var PATHTOPAGES = "Pages";
// file name only for template page, no extension
var TEMPLATEFILENAME = "Template";
var myPathToWiki = encodeURIComponent(PATHTOWIKI);
var myPathToPages = PATHTOPAGES + "%2f";
var myTemplateFileName = encodeURIComponent(TEMPLATEFILENAME) + "%2easpx";
var EnteredProject = document.getElementById("NewProjName");
var myNewName = EnteredProject.value;
if(myNewName == "") {
alert('Please enter a name for the new project page');
} else {
myNewName = encodeURIComponent(myNewName) + "%2easpx"
$.ajax({
url: PATHTOWIKI + "/_vti_bin/_vti_aut/author.dll",
data: ( "method=move+document%3a14%2e0%2e0%2e4730&service%5fname="
+ myPathToWiki +
"&oldUrl=" + myPathToPages + myTemplateFileName +
"&newUrl=" + myPathToPages + myNewName +
"&url%5flist=%5b%5d&rename%5foption=nochangeall&put%5foption=edit&docopy=true"
),
success: function(data) {
var rpcmsg1 = getMessage(data, "message=", "<p>");
$("#myInfo").append("<br />" + rpcmsg1);
if(rpcmsg1.indexOf("successfully") < 0) {
// get error info
var rpcmsg2 = getMessage(data, "msg=", "<li>");
$("#myInfo").append("<br />" + rpcmsg2 + "<br />");
} else {
$("#myInfo").append("<br />Go to new page<br />");
}
},
type: "POST",
beforeSend: function(XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("X-Vermeer-Content-Type",
"application/x-www-form-urlencoded");
}
});
}
}
Update: I figured out what needed to happen in my case. Since I couldn't get a grasp on the relative approach, I just went with the absolute path for PATHTOWIKI and slightly modified the append in the ajax call.
PATHTOWIKI:
var PATHTOWIKI = "https://[domain]/sites/[parentSite]/[childSite]";
append:
$("#myInfo").append("<br />Go to new page<br />");
The change in the latter line of code is subtle; since I used an absolute path in PATHTOWIKI, I just removed the leading forward slash in the anchor tag, so that <a href=\"/" became <a href=\"". This renders the script slightly less portable, but since it's a one-off effort I'll stick with this unless anything comes along to expand the scope.

jmeter testcases which can handle captcha?

We are trying to build a jmeter testcase which does the following:
login to a system
obtain some information and check whether correct.
Where we are facing issues is because there is a captcha while logging into the system. What we had planned to do was to download the captcha link and display, and wait for user to type in the value. Once done, everything goes as usual.
We couldnt find any plugin that can do the same? Other than writing our own plugin, is there any option here?
I was able to solve it myself. The solution is as follows:
Create a JSR223 PostProcessor (using Groovy)
more practical CAPTCHA example with JSESSIONID handling and proxy setting
using image.flush() to prevent stale CAPTCHA image in dialog box
JSR223 Parameters for proxy connection setting:
Parameters: proxy 10.0.0.1 8080
In it, the following code displays the captcha and waits for user input
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.Icon;
import javax.swing.JOptionPane;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.protocol.http.control.CookieManager;
import org.apache.jmeter.protocol.http.control.Cookie;
URL urlTemp ;
urlTemp = new URL( "https://your.domainname.com/endpoint/CAPTCHACode");
HttpURLConnection myGetContent = null;
if(args[0]=="proxy" ){
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(args[1], Integer.parseInt(args[2])));
myGetContent = (HttpURLConnection) urlTemp.openConnection(proxy);
}else{
myGetContent = (HttpURLConnection) urlTemp.openConnection();
}
// false for http GET
myGetContent.setDoOutput(false);
myGetContent.connect();
int status = myGetContent.getResponseCode();
log.info("HTTP Status Code: "+Integer.toString(status));
if (status == HttpURLConnection.HTTP_OK) {
//We have 2 Set-Cookie headers in response message but 1 Set-Cookie entry in Map
String[] parts2;
for (Map.Entry<String, List<String>> entries : myGetContent.getHeaderFields().entrySet()) {
if( entries.getKey() == "Set-Cookie" ){
for (String value : entries.getValue()) {
if ( value.contains("JSESSIONID") == true ){
String[] parts = value.split(";",2);
log.info("Response header: "+ entries.getKey() + " - " + parts[0] );
JMeterContext context = JMeterContextService.getContext();
CookieManager manager = context.getCurrentSampler().getCookieManager();
parts2 = parts[0].split("=",2)
Cookie cookie = new Cookie("JSESSIONID",parts2[1],"your.domainname.com","/endpoint",true,0, true, true, 0);
manager.add(cookie);
log.info( cookie.toString() );
log.info("CookieCount "+ manager.getCookieCount().toString() );
}
}
}
}//end of outer for loop
if ( parts2.find() == null ) {
throw new Exception("The Response Header not contain Set-Cookie:JSESSIONID= .");
}
}else{
throw new Exception("The Http Status Code was ${status} , not expected 200 OK.");
}
BufferedInputStream bins = new BufferedInputStream(myGetContent.getInputStream());
String destFile = "number.png";
File f = new File(destFile);
if(f.exists() ) {
boolean fileDeleted = f.delete();
log.info("delete file ... ");
log.info(String.valueOf(fileDeleted));
}
FileOutputStream fout =new FileOutputStream(destFile);
int m = 0;
byte[] bytesIn = new byte[1024];
while ((m = bins.read(bytesIn)) != -1) {
fout.write(bytesIn, 0, m);
}
fout.close();
bins.close();
log.info("File " +destFile +" downloaded successfully");
Image image = Toolkit.getDefaultToolkit().getImage(destFile);
image.flush(); // release the prior cache of Captcha image
Icon icon = new javax.swing.ImageIcon(image);
JOptionPane pane = new JOptionPane("Enter Captcha", 0, 0, null);
String captcha = pane.showInputDialog(null, "Captcha", "Captcha", 0, icon, null, null);
captcha = captcha.trim();
captcha = captcha.replaceAll("\r\n", "");
log.info(captcha);
vars.put("captcha", captcha);
myGetContent.disconnect();
By vars.put method we can use the captcha variable in any way we want. Thank you everyone who tried to help.
Since CAPTHA used to detect non-humans, JMeter will always fail it.
You have to make a workaround in your software: either disable captcha requesting or print somewhere on page correct captcha. Of course, only for JMeter tests.
Dirty workaround? Print the captcha value in alt image for the tests. And then you can retrieve the value and go on.