Wednesday, March 26, 2008

C# test automation with Internet Explorer

As a follow up on my previous post, I had the idea you can do the same in managed code (in your test library, for instance). Although this won't exactly be a unit test (especialy with the example search form, it's more integration testing), it can be usefull in some scenarios.

You need a reference to two COM dll's,
MSHTML
Microsoft HTML Object Library
SHDocVw
Microsoft Internet Controls


After that, you can use the following example code inside your test (I present it here as one block. Some things can be put in test setup and teardown):

SHDocVw.InternetExplorer ie = new SHDocVw.InternetExplorerClass();
object missing = new object();
ie.Navigate("http://localhost/Default.aspx", ref missing, ref missing, ref missing, ref missing);
ie.Visible = true;
while (ie.Busy)
{
System.Threading.Thread.Sleep(500);
}
mshtml.HTMLDocumentClass doc = ie.Document as mshtml.HTMLDocumentClass;
doc.getElementById("searchbox").setAttribute("value", "test", 0);
doc.getElementById("searchsubmit").click();
while (ie.Busy)
{
System.Threading.Thread.Sleep(500);
}
string bodytext = doc.body.innerHTML;
Debug.Assert( bodytext.IndexOf("documents found")>0);

ie.Quit();

PowerShell Web UI test automation

Just read an article in MSDN magazine about test automation for Internet Explorer so you can test your web user interface. There are other tools for this (like Selenium), but those need quite a setup.

Execute a search-box test in PowerShell:

$ie = new-object -com "InternetExplorer.Application"
$ie.navigate("http://localhost/Default.aspx")
$ie.visible = $true
$doc = $ie.document
$doc.getElementByID("searchbox").value = "test"
$doc.getElementByID("searchsubmit").click()

Monday, March 17, 2008

Dutch 'Webrichtlijnen' and binary downloads

The Dutch Web Guidelines (a quality model for sustainable and accessible websites) describe what to do with downloads on your page. This isn't meant for HTML and images, but when you place Adobes Protable Document Format (pdf) or Rich Text Documents (rtf), those documents can be opened in your current window. It is possible to open those files in new windows (although the target="_blank" solution doesn't conform to XHTML validation, some solutions do exist , like rel="external" and JavaScript replacement). But this can be a browser window. Although you can configure your browser, the majority of users don't have the knowledge to tweak their browser to do what they want with these files.
The solution from the Webrichtlijnen:

Do not automatically open links to downloadable files in a new window.


Guideline R-pd.8.22


One way of getting this done is setting the HTTP Content-disposition header
By having the web server send an extra HTTP header for the downloadable file to the browser, the browser can decide whether to download this file untouched as an attachment to the visitor's hard disk.

The best way to do this is writing a custom HTTP Module which can check on served file extensions or MIME Types and add the content disposition header for configured downloads.
In this example implementation, I configure the file extensions in code, but you can always configure this in your config, database or any file.


public class ContentDispositionModule : IHttpModule
{
#region IHttpModule Members

///<summary>
///Initializes the module and prepares it to handle requests.
///</summary>
///<param name="context">An <see cref="T:System.Web.HttpApplication"></see>
///that provides access to the methods, properties, and events common
///to all application objects within an ASP.NET application </param>
public virtual void Init(HttpApplication context)
{
context.PreSendRequestHeaders += new EventHandler(SetContentDispositionHeader);
}

private static void SetContentDispositionHeader(object sender, EventArgs e)
{
string url = ((HttpApplication)sender).Context.Request.Path;
if (IsUrlPatternMatch(url))
{
((HttpApplication)sender).Context.Response.AppendHeader("Content-Disposition", "attachment");
}
}

///<summary>
///Disposes of the resources (other than memory) used by the module that implements
///<see cref="T:System.Web.IHttpModule"></see>.
///</summary>
public virtual void Dispose()
{
}

/// <summary>
/// Check the url against the binaryExtension patterns
/// </summary>
/// <param name="strUrl">url to check</param>
/// <returns>true if it matches the binaryExtension pattern</returns>
private static bool IsUrlPatternMatch(string strUrl)
{
// get this string from a more configurable place.
string binaryExtensions = "*.pdf,*.rtf";
if (!string.IsNullOrEmpty(binaryExtensions))
{
foreach (string extension in binaryExtensions.Split(','))
{
if (!string.IsNullOrEmpty(extension))
{
if (Regex.IsMatch(strUrl, extension.Trim()))
{
// the url path contains the specified regex string, so return true and break out of loop
return true;
}
}
}
}
return false;
}

#endregion
}


After coding this module, you'll need to change the .config so the module will be activated for usage. Add it to the httpModules of the system.web section. You'll also need to configure IIS that all needed extensions are routed through your ASP.NET ISAPI dll.

Friday, March 14, 2008

MCPD - EAD

Yesterday I had my 70-554 exam, and fortunately I passed with 880! It was a hard and difficult exam, so I was really glad to see this number on my screen.
I'm now certified for:
  • Microsoft Certified Technology Specialist: .NET Framework 2.0 Distributed Applications

  • Microsoft Certified Professional Developer: Enterprise Application Developer


Thursday, March 13, 2008

LINQ Design Guidelines

Mircea Trofin is writing on his blog some design guidelines for writing .NET LINQ code. It gives you a quick start to design qualitatively LINQ code.