<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Muranosoft Blog - Quality Assurance</title>
    <link>http://www.muranosoft.com/Outsourcingblog/</link>
    <description>Coding etc</description>
    <language>en-us</language>
    <copyright>Murano Software</copyright>
    <lastBuildDate>Thu, 04 Feb 2010 19:42:00 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>valerie.sinitskaya@muranosoft.com</managingEditor>
    <webMaster>valerie.sinitskaya@muranosoft.com</webMaster>
    <item>
      <trackback:ping>http://www.muranosoft.com/Outsourcingblog/Trackback.aspx?guid=d98815bc-fb9b-4abd-8866-74c13ff3313e</trackback:ping>
      <pingback:server>http://www.muranosoft.com/Outsourcingblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.muranosoft.com/Outsourcingblog/PermaLink,guid,d98815bc-fb9b-4abd-8866-74c13ff3313e.aspx</pingback:target>
      <dc:creator>Muranosoft admin</dc:creator>
      <wfw:comment>http://www.muranosoft.com/Outsourcingblog/CommentView,guid,d98815bc-fb9b-4abd-8866-74c13ff3313e.aspx</wfw:comment>
      <wfw:commentRss>http://www.muranosoft.com/Outsourcingblog/SyndicationService.asmx/GetEntryCommentsRss?guid=d98815bc-fb9b-4abd-8866-74c13ff3313e</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <em>By Sergey, a quality assurance manager on Murano Software’s team</em>
        </p>
        <p>
If you have ever tried to upload a file under <a href="http://seleniumhq.org/projects/remote-control/">Selenium
RC</a>, you must know that it is impossible to type in the file upload text field.
This caused by a JavaScript security restriction. JavaScript is not allowed to modify
the value of &lt;input type="file"&gt; form fields. <a href="http://wiki.openqa.org/">http://wiki.openqa.org</a> suggests
to work around this by running the tests in the experimental “chrome” mode for Firefox.
But it is mentioned that there is no way to do this on any other browser.
</p>
        <p>
I have tried to use the “chrome” mode for Firefox and the “iehta” mode for IE, but
my tests turned out very unstable. Fortunately, there is another workaround.
</p>
        <p>
For Firefox and IE, you can set the focus inside the file upload field by using JavaScript. 
</p>
        <div style="border: solid 1px silver;">
          <pre class="brush: js; toolbar: true; gutter: false; bloggerMode:true;">
selenium.getEval("this.browserbot.getCurrentWindow().document.getElementById('FileUploadFieldId').focus();")
</pre>
        </div>
        <p>
Then use the selenium.keyPressNative () method to type the file path, i.e. C:\Some
Folder\TestFile.txt. The method simulates a user pressing and releasing a key by sending
a native operating system keystroke. I created a helper method to type the file path.
It handles upper case and lower case letters, back slashes, spaces and periods.
</p>
        <div style="border: solid 1px silver;">
          <pre class="brush: java; toolbar: true; gutter: false; bloggerMode:true;">
import java.awt.event.KeyEvent

protected void typeNative(String filePath) throws InterruptedException 
{
  for (char c : filePath.toCharArray()) {
    if (c == ':') {
      selenium.keyDownNative(Integer.toString(KeyEvent.VK_SHIFT));
      selenium.keyPressNative(Integer.toString(KeyEvent.VK_SEMICOLON));
      selenium.keyUpNative(Integer.toString(KeyEvent.VK_SHIFT));
    }
    else if (c == '\\') {
      selenium.keyPressNative(Integer.toString(KeyEvent.VK_BACK_SLASH));
    }
    else if (c == '.') {
      selenium.keyPressNative(Integer.toString(KeyEvent.VK_PERIOD));
    }
    else if (c == ' ') {
      selenium.keyPressNative(Integer.toString(KeyEvent.VK_SPACE));
    }
    else {
      KeyStroke key = KeyStroke.getKeyStroke("pressed " + Character.toUpperCase(c));
      if (null != key) {
        // should only have to worry about case with standard characters
        if (Character.isUpperCase(c)) {
          selenium.keyDownNative(Integer.toString(KeyEvent.VK_SHIFT));
        }
        selenium.keyPressNative(Integer.toString(key.getKeyCode()));
 
        if (Character.isUpperCase(c)) {
          selenium.keyUpNative(Integer.toString(KeyEvent.VK_SHIFT));
        }
      }
    }
  }
}
</pre>
        </div>
        <p>
If you're using Selenium RC and Java, you can exploit java.awt.Robot, instead of using
the selenium.keyPressNative() method. See the code sample below.
</p>
        <p>
For Safari, there is no rendered field in the HTML page into which you can simply
type keys. Safari requires that the user interact with a “File Upload” dialog box.
To get the dialog, you can put selenium.click() on the file upload field. But here
you will meet another unpleasant surprise. The “File Upload” dialog box will be loaded
in a modal window, so the executing of your code will be held up until the modal window
is closed.
</p>
        <p>
To handle that, you need to invoke the type native method in the other thread one
step before clicking on the file upload field and set a delay to wait until the modal
window with the “File Upload” dialog box appears. See the code sample that uses java.awt.Robot.
</p>
        <div style="border: solid 1px silver;">
          <pre class="brush: java; toolbar: true; gutter: false; bloggerMode:true;">
protected void chooseFile(String element, String filePath) throws InterruptedException
{
  new FileChooserThread(filePath).start();
  selenium.click(element);
}
</pre>
        </div>
        <p>
To invoke the type native method, just add new class containing the code below to
your project.
</p>
        <div style="border: solid 1px silver;">
          <pre class="brush: java; toolbar: true; gutter: false; bloggerMode:true;">
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
 
public class FileChooserThread extends Thread 
{
  public FileChooserThread(String file) {
    super(new FileRunner(file));
  }
}
 
class FileRunner implements Runnable 
{
  private String fullName;
 
  public FileRunner(String fileName) {
    this.fullName = fileName;
  }
 
  public void run() {
    try {
      Thread.sleep(2000);
      Robot robot = new Robot(); // input simulation class
      for (char c : fullName.toCharArray()){
        if (c == ':') {
          robot.keyPress(KeyEvent.VK_SHIFT);
          robot.keyPress(KeyEvent.VK_SEMICOLON);
          robot.keyRelease(KeyEvent.VK_SHIFT);
        }
        else if (c == '\\') {
          robot.keyPress(KeyEvent.VK_BACK_SLASH);
        }
        else if (c == '.') {
          robot.keyPress(KeyEvent.VK_PERIOD);
        }
        else if (c == ' ') {
          robot.keyPress(KeyEvent.VK_SPACE);
        }
        else {
          KeyStroke key = KeyStroke.getKeyStroke("pressed " + Character.toUpperCase(c));
          if (null != key) {
            // should only have to worry about case with standard characters
            if (Character.isUpperCase(c)) {
              robot.keyPress(KeyEvent.VK_SHIFT);
            }
 
            robot.keyPress(key.getKeyCode());
            robot.keyRelease(key.getKeyCode());
 
            if (Character.isUpperCase(c)) {
              robot.keyRelease(KeyEvent.VK_SHIFT);
            }
          }
        }
      }
      robot.keyPress(KeyEvent.VK_ENTER);
    }
    catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
}
</pre>
        </div>
        <p>
The final remark is addressed to the focus. This workaround will work only if the
system focus is into the file upload field. I had to start the selenium server with
the <b>-multiWindow</b> parameter to set the system focus into the browser window.
</p>
        <script type="text/javascript"> 
  SyntaxHighlighter.config.clipboardSwf = 'syntaxhighlighter/scripts/clipboard.swf';
  SyntaxHighlighter.all();
</script>
        <img width="0" height="0" src="http://www.muranosoft.com/Outsourcingblog/aggbug.ashx?id=d98815bc-fb9b-4abd-8866-74c13ff3313e" />
      </body>
      <title>Upload file with Selenium</title>
      <guid isPermaLink="false">http://www.muranosoft.com/Outsourcingblog/PermaLink,guid,d98815bc-fb9b-4abd-8866-74c13ff3313e.aspx</guid>
      <link>http://www.muranosoft.com/Outsourcingblog/Upload-File-With-Selenium.aspx</link>
      <pubDate>Thu, 04 Feb 2010 19:42:00 GMT</pubDate>
      <description>&lt;p&gt;
&lt;em&gt;By Sergey, a quality assurance manager on Murano Software’s team&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
If you have ever tried to upload a file under &lt;a href="http://seleniumhq.org/projects/remote-control/"&gt;Selenium
RC&lt;/a&gt;, you must know that it is impossible to type in the file upload text field.
This caused by a JavaScript security restriction. JavaScript is not allowed to modify
the value of &amp;lt;input type=&amp;quot;file&amp;quot;&amp;gt; form fields. &lt;a href="http://wiki.openqa.org/"&gt;http://wiki.openqa.org&lt;/a&gt; suggests
to work around this by running the tests in the experimental “chrome” mode for Firefox.
But it is mentioned that there is no way to do this on any other browser.
&lt;/p&gt;
&lt;p&gt;
I have tried to use the “chrome” mode for Firefox and the “iehta” mode for IE, but
my tests turned out very unstable. Fortunately, there is another workaround.
&lt;/p&gt;
&lt;p&gt;
For Firefox and IE, you can set the focus inside the file upload field by using JavaScript. 
&lt;/p&gt;
&lt;div style="border: solid 1px silver;"&gt;
&lt;pre class="brush: js; toolbar: true; gutter: false; bloggerMode:true;"&gt;
selenium.getEval("this.browserbot.getCurrentWindow().document.getElementById('FileUploadFieldId').focus();")
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Then use the selenium.keyPressNative () method to type the file path, i.e. C:\Some
Folder\TestFile.txt. The method simulates a user pressing and releasing a key by sending
a native operating system keystroke. I created a helper method to type the file path.
It handles upper case and lower case letters, back slashes, spaces and periods.
&lt;/p&gt;
&lt;div style="border: solid 1px silver;"&gt;
&lt;pre class="brush: java; toolbar: true; gutter: false; bloggerMode:true;"&gt;
import java.awt.event.KeyEvent

protected void typeNative(String filePath) throws InterruptedException 
{
  for (char c : filePath.toCharArray()) {
    if (c == ':') {
      selenium.keyDownNative(Integer.toString(KeyEvent.VK_SHIFT));
      selenium.keyPressNative(Integer.toString(KeyEvent.VK_SEMICOLON));
      selenium.keyUpNative(Integer.toString(KeyEvent.VK_SHIFT));
    }
    else if (c == '\\') {
      selenium.keyPressNative(Integer.toString(KeyEvent.VK_BACK_SLASH));
    }
    else if (c == '.') {
      selenium.keyPressNative(Integer.toString(KeyEvent.VK_PERIOD));
    }
    else if (c == ' ') {
      selenium.keyPressNative(Integer.toString(KeyEvent.VK_SPACE));
    }
    else {
      KeyStroke key = KeyStroke.getKeyStroke("pressed " + Character.toUpperCase(c));
      if (null != key) {
        // should only have to worry about case with standard characters
        if (Character.isUpperCase(c)) {
          selenium.keyDownNative(Integer.toString(KeyEvent.VK_SHIFT));
        }
        selenium.keyPressNative(Integer.toString(key.getKeyCode()));
 
        if (Character.isUpperCase(c)) {
          selenium.keyUpNative(Integer.toString(KeyEvent.VK_SHIFT));
        }
      }
    }
  }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
If you're using Selenium RC and Java, you can exploit java.awt.Robot, instead of using
the selenium.keyPressNative() method. See the code sample below.
&lt;/p&gt;
&lt;p&gt;
For Safari, there is no rendered field in the HTML page into which you can simply
type keys. Safari requires that the user interact with a “File Upload” dialog box.
To get the dialog, you can put selenium.click() on the file upload field. But here
you will meet another unpleasant surprise. The “File Upload” dialog box will be loaded
in a modal window, so the executing of your code will be held up until the modal window
is closed.
&lt;/p&gt;
&lt;p&gt;
To handle that, you need to invoke the type native method in the other thread one
step before clicking on the file upload field and set a delay to wait until the modal
window with the “File Upload” dialog box appears. See the code sample that uses java.awt.Robot.
&lt;/p&gt;
&lt;div style="border: solid 1px silver;"&gt;
&lt;pre class="brush: java; toolbar: true; gutter: false; bloggerMode:true;"&gt;
protected void chooseFile(String element, String filePath) throws InterruptedException
{
  new FileChooserThread(filePath).start();
  selenium.click(element);
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
To invoke the type native method, just add new class containing the code below to
your project.
&lt;/p&gt;
&lt;div style="border: solid 1px silver;"&gt;
&lt;pre class="brush: java; toolbar: true; gutter: false; bloggerMode:true;"&gt;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
 
public class FileChooserThread extends Thread 
{
  public FileChooserThread(String file) {
    super(new FileRunner(file));
  }
}
 
class FileRunner implements Runnable 
{
  private String fullName;
 
  public FileRunner(String fileName) {
    this.fullName = fileName;
  }
 
  public void run() {
    try {
      Thread.sleep(2000);
      Robot robot = new Robot(); // input simulation class
      for (char c : fullName.toCharArray()){
        if (c == ':') {
          robot.keyPress(KeyEvent.VK_SHIFT);
          robot.keyPress(KeyEvent.VK_SEMICOLON);
          robot.keyRelease(KeyEvent.VK_SHIFT);
        }
        else if (c == '\\') {
          robot.keyPress(KeyEvent.VK_BACK_SLASH);
        }
        else if (c == '.') {
          robot.keyPress(KeyEvent.VK_PERIOD);
        }
        else if (c == ' ') {
          robot.keyPress(KeyEvent.VK_SPACE);
        }
        else {
          KeyStroke key = KeyStroke.getKeyStroke("pressed " + Character.toUpperCase(c));
          if (null != key) {
            // should only have to worry about case with standard characters
            if (Character.isUpperCase(c)) {
              robot.keyPress(KeyEvent.VK_SHIFT);
            }
 
            robot.keyPress(key.getKeyCode());
            robot.keyRelease(key.getKeyCode());
 
            if (Character.isUpperCase(c)) {
              robot.keyRelease(KeyEvent.VK_SHIFT);
            }
          }
        }
      }
      robot.keyPress(KeyEvent.VK_ENTER);
    }
    catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
The final remark is addressed to the focus. This workaround will work only if the
system focus is into the file upload field. I had to start the selenium server with
the &lt;b&gt;-multiWindow&lt;/b&gt; parameter to set the system focus into the browser window.
&lt;/p&gt;
&lt;script type="text/javascript"&gt; 
  SyntaxHighlighter.config.clipboardSwf = 'syntaxhighlighter/scripts/clipboard.swf';
  SyntaxHighlighter.all();
&lt;/script&gt;
&lt;img width="0" height="0" src="http://www.muranosoft.com/Outsourcingblog/aggbug.ashx?id=d98815bc-fb9b-4abd-8866-74c13ff3313e" /&gt;</description>
      <comments>http://www.muranosoft.com/Outsourcingblog/CommentView,guid,d98815bc-fb9b-4abd-8866-74c13ff3313e.aspx</comments>
      <category>Quality Assurance</category>
      <category>Software Development</category>
    </item>
    <item>
      <trackback:ping>http://www.muranosoft.com/Outsourcingblog/Trackback.aspx?guid=6e91891a-20eb-4db1-8bd2-0342f82c4041</trackback:ping>
      <pingback:server>http://www.muranosoft.com/Outsourcingblog/pingback.aspx</pingback:server>
      <pingback:target>http://www.muranosoft.com/Outsourcingblog/PermaLink,guid,6e91891a-20eb-4db1-8bd2-0342f82c4041.aspx</pingback:target>
      <dc:creator>Muranosoft admin</dc:creator>
      <wfw:comment>http://www.muranosoft.com/Outsourcingblog/CommentView,guid,6e91891a-20eb-4db1-8bd2-0342f82c4041.aspx</wfw:comment>
      <wfw:commentRss>http://www.muranosoft.com/Outsourcingblog/SyndicationService.asmx/GetEntryCommentsRss?guid=6e91891a-20eb-4db1-8bd2-0342f82c4041</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <em>By Sergey and Maxim, a Quality Assurance Manager and a <a href="/services/microsoftnet.aspx">.NET
Developer</a> on Murano Software’s team.</em>
        </p>
        <p>
If you have ever worked with <a href="http://en.wikipedia.org/wiki/Selenium_%28software%29">Selenium</a>,
you may find XPath a convenient alternative to walking through document trees. In
case you are using Firefox, XPath remains an opportune and fast way to find specific
elements without walking the DOM manually. Unfortunately, it works tremendously slowly
in IE 6 and IE 7. Recently, we faced this problem, and now we’re happy to share our
elegant solution with you. 
</p>
        <p>
To solve the speed problem in IE, we tried to replace XPath selectors with CSS ones.
It gave us a 10x speed up in IE. Impressive, but by using CSS, we lost a very useful
feature that XPath offers. In Xpath, we can use the ‘..’ expression to select the
parent of the current node. This feature is necessary when you need to click a button
next to the element having a particular name in the list of elements. See the sample
below. 
</p>
        <blockquote>
          <code>
            <font color="#000000" size="2" face="Courier New">
              <font color="#0000ff">&lt;</font>
              <font color="#800000">table</font>
              <font color="#ff0000">class</font>
              <font color="#0000ff">="style"</font>
              <font color="#0000ff">&gt;</font>
              <br />
    <font color="#0000ff">&lt;</font><font color="#800000">tr</font><font color="#ff0000">class</font><font color="#0000ff">="somestyle"</font><font color="#0000ff">&gt;</font><br />
        <font color="#0000ff">&lt;</font><font color="#800000">td</font><font color="#0000ff">&gt;</font>SomeName1<font color="#0000ff">&lt;/</font><font color="#800000">td</font><font color="#0000ff">&gt;</font><br />
        <font color="#0000ff">&lt;</font><font color="#800000">td</font><font color="#0000ff">&gt;</font><br />
            <font color="#0000ff">&lt;</font><font color="#800000">input</font><font color="#ff0000">type</font><font color="#0000ff">="submit"</font><font color="#ff0000">value</font><font color="#0000ff">="Edit"</font><font color="#ff0000">class</font><font color="#0000ff">="btn"</font><font color="#0000ff">/&gt;</font><br />
        <font color="#0000ff">&lt;/</font><font color="#800000">td</font><font color="#0000ff">&gt;</font><br />
    <font color="#0000ff">&lt;/</font><font color="#800000">tr</font><font color="#0000ff">&gt;</font><br />
    <font color="#0000ff">&lt;</font><font color="#800000">tr</font><font color="#ff0000">class</font><font color="#0000ff">="gvAlternatingRowH35"</font><font color="#0000ff">&gt;</font><br />
        <font color="#0000ff">&lt;</font><font color="#800000">td</font><font color="#0000ff">&gt;</font>SomeName2<font color="#0000ff">&lt;/</font><font color="#800000">td</font><font color="#0000ff">&gt;</font><br />
        <font color="#0000ff">&lt;</font><font color="#800000">td</font><font color="#0000ff">&gt;</font><br />
            <font color="#0000ff">&lt;</font><font color="#800000">input</font><font color="#ff0000">type</font><font color="#0000ff">="submit"</font><font color="#ff0000">value</font><font color="#0000ff">="Edit"</font> <font color="#ff0000">class</font><font color="#0000ff">="btn"</font><font color="#0000ff">/&gt;</font><br />
        <font color="#0000ff">&lt;/</font><font color="#800000">td</font><font color="#0000ff">&gt;</font><br />
    <font color="#0000ff">&lt;/</font><font color="#800000">tr</font><font color="#0000ff">&gt;</font><br /><font color="#0000ff">&lt;/</font><font color="#800000">table</font><font color="#0000ff">&gt;</font><br /></font>
            <br />
          </code>
        </blockquote>
        <p>
All the buttons have the same attributes.  If you want to click the “Edit” button
next to SomeName2, you can easily complete this task in selenium by using XPath and
its parent feature:
</p>
        <blockquote>
          <code>
            <font color="#000000" size="2" face="Courier New">selenium.click(<font color="#a31515">"//td[text()='SomeName2']/../td/input[@value='Edit']"</font>)</font>
            <br />
            <br />
          </code>
        </blockquote>
        <p>
As we mentioned above, this won’t be that easy to do with CSS because it doesn’t have
the appropriate feature. So, we used the JQuery parent() function to have the ability
to select the parent of the current node. It works really fast in all browsers, since
JQuery uses CSS.  
</p>
        <p>
We added  Jquery’s library to the Selenium server (see steps 1 and 2 below) and
executed JQuery script directly from Selenium. To execute JQuery script, you can use <strong>selenium.getEval(someJS)</strong> if
you need the return value, or <strong>selenium.runScript(someJS)</strong> if you don’t. 
</p>
        <p>
But that was not enough for us. We wanted to select the parent element by using the
easy syntaxes of CSS locators. To use them, we had to add a new custom locator to
Selenium. Below, find the three easy steps that we took to add a custom locator. 
</p>
        <p>
          <strong>
            <font size="3">1. Add Jquery’s library to Selenium server.</font>
          </strong>
        </p>
        <p>
Add JQuery’s library (‘jquery.min.js’) to your selenium-server.jar (‘selenium-server.jar\core\scripts\’
folder). To do that, open ‘selenium-server.jar’ by using one of the archives — for
example, 7-Zip — and drag-and-drop ‘jquery.min.js’ in the mentioned folder. 
</p>
        <p>
          <strong>
          </strong>
        </p>
        <p>
          <strong>
            <font size="3">2. Add script reference to JQuery library.</font>
          </strong>
        </p>
        <p>
Add script reference to ‘jquery.min.js’ to the ‘&lt;head&gt;’ section of the RemoteRunner.html
(‘selenium-server.jar\core\’).
</p>
        <blockquote>
          <code>
            <font color="#000000" size="2" face="Courier New">
              <font color="#0000ff">&lt;</font>
              <font color="#800000">head</font>
              <font color="#0000ff">&gt;</font>
              <br />
... 
<br /><font color="#0000ff">&lt;</font><font color="#800000">script</font><font color="#ff0000">language</font><font color="#0000ff">="JavaScript"</font><font color="#ff0000">type</font><font color="#0000ff">="text/javascript" </font><font color="#ff0000">src</font><font color="#0000ff">="scripts/jquery.min.js"</font><font color="#0000ff">/&gt;</font><br />
... 
<br /><font color="#0000ff">&lt;\</font><font color="#800000">head</font><font color="#0000ff">&gt;</font><br /></font>
            <br />
          </code>
        </blockquote>
        <p>
          <strong>
            <font size="3">3. Add new JQuery locator to Selenium core.</font>
          </strong>
        </p>
        <p>
You can add a new JQuery locator to the Selenium core in the <strong>runSeleniumTest()</strong> function
of the selenium-remoterunner.js file. All you need to do is to add a call of <strong>selenium.doAddLocationStrategy()</strong> method
before Selenium property initialization of the window object. See the sample below
for more details. 
</p>
        <blockquote>
          <code>
            <font color="#000000" size="2" face="Courier New">
              <font color="#0000ff">function</font> runSeleniumTest()
{ 
<br />
    ... 
<br />
    selenium.doAddLocationStrategy("jquery", " 
<br />
var loc = <font color="#0000ff">locator</font>; 
<br />
var attr = <font color="#0000ff">null</font>; 
<br />
var isattr = <font color="#0000ff">false</font>; 
<br />
var inx = <font color="#0000ff">locator</font>.lastIndexOf(<font color="#a31515">'@'</font>); 
<br /><br /><font color="#0000ff">if</font> (inx != -1) { 
<br />
    loc = <font color="#0000ff">locator</font>.<font color="#0000ff">substring</font>(0,
inx); 
<br />
    attr = <font color="#0000ff">locator</font>.<font color="#0000ff">substring</font>(inx
+ 1); 
<br />
    isattr = <font color="#0000ff">true</font><br />
} 
<br /><br />
var selectors = loc.split(<font color="#a31515">'&lt;'</font>); 
<br />
var <font color="#0000ff">found</font> = $(inDocument); 
<br /><br /><font color="#0000ff">for</font> (var i = 0; i &lt; selectors.length; i++) { 
<br />
    <font color="#0000ff">if</font> (i &gt; 0) {<font color="#0000ff">found</font> =
$(<font color="#0000ff">found</font>.parents()[0]); 
<br />
} 
<br /><br /><font color="#0000ff">if</font> (jQuery.<font color="#0000ff">trim</font>(selectors[i])
!= <font color="#a31515">''</font>) 
<br />
    <font color="#0000ff">found</font> = <font color="#0000ff">found</font>.find(selectors[i]); 
<br />
} 
<br /><br /><font color="#0000ff">if</font> (<font color="#0000ff">found</font>.length &gt; 0)
{ 
<br />
    <font color="#0000ff">if</font> (isattr) { 
<br />
        <font color="#0000ff">return</font><font color="#0000ff">found</font>[0].getAttributeNode(attr); 
<br />
    } 
<br />
    <font color="#0000ff">else</font> { 
<br />
        <font color="#0000ff">return</font><font color="#0000ff">found</font>[0]; 
<br />
    } 
<br />
} 
<br /><font color="#0000ff">else</font> { 
<br />
    <font color="#0000ff">return</font><font color="#0000ff">null</font>; 
<br />
} 
<br />
    "); 
<br />
    ... 
<br />
} 
<br /></font>
            <br />
          </code>
        </blockquote>
        <p>
The first parameter of the <strong>selenium.doAddLocationStrategy</strong> method
(“JQuery”) is the new Selenium locator’s name. The second one (“var loc = locator…”)
is the new custom Selenium locator. If you want to, you can write your own implementation
for the locator. To call the JQuery parent() function, we used the '&lt;' custom symbol
.  
</p>
        <p>
Finally, let’s take a look at how you can use the new JQuery locators, instead of
the XPath ones. 
</p>
        <p>
XPath locators: 
<br />
•    xpath=//a[contains(@href,'#id1')] 
<br />
•    xpath=(//table[@class='stylee'])//th[text()='theHeaderText']/../td 
<br />
•    xpath=//input[@name='name2' and @value='yes'] 
</p>
        <p>
JQuery locators: 
<br />
•    jquery= a[href*='#id1'] 
<br />
•    jquery= table[class='stylee'] th:contains('theHeaderText')&lt;td 
<br />
•    jquery= input[name='name2'][value='yes'] 
</p>
        <p>
We hope you’ll find our experience useful to you. Also, we’d be happy to answer your
questions if you have any!
</p>
        <img width="0" height="0" src="http://www.muranosoft.com/Outsourcingblog/aggbug.ashx?id=6e91891a-20eb-4db1-8bd2-0342f82c4041" />
      </body>
      <title>How to Use JQuery Instead of XPath Locators in Selenium Testing Framework</title>
      <guid isPermaLink="false">http://www.muranosoft.com/Outsourcingblog/PermaLink,guid,6e91891a-20eb-4db1-8bd2-0342f82c4041.aspx</guid>
      <link>http://www.muranosoft.com/Outsourcingblog/How-To-Use-JQuery-Instead-Of-XPath-Locators-In-Selenium-Testing-Framework.aspx</link>
      <pubDate>Wed, 18 Nov 2009 11:29:25 GMT</pubDate>
      <description>&lt;p&gt;
&lt;em&gt;By Sergey and Maxim, a Quality Assurance Manager and a &lt;a href="/services/microsoftnet.aspx"&gt;.NET
Developer&lt;/a&gt; on Murano Software’s team.&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
If you have ever worked with &lt;a href="http://en.wikipedia.org/wiki/Selenium_%28software%29"&gt;Selenium&lt;/a&gt;,
you may find XPath a convenient alternative to walking through document trees. In
case you are using Firefox, XPath remains an opportune and fast way to find specific
elements without walking the DOM manually. Unfortunately, it works tremendously slowly
in IE 6 and IE 7. Recently, we faced this problem, and now we’re happy to share our
elegant solution with you. 
&lt;/p&gt;
&lt;p&gt;
To solve the speed problem in IE, we tried to replace XPath selectors with CSS ones.
It gave us a 10x speed up in IE. Impressive, but by using CSS, we lost a very useful
feature that XPath offers. In Xpath, we can use the ‘..’ expression to select the
parent of the current node. This feature is necessary when you need to click a button
next to the element having a particular name in the list of elements. See the sample
below. 
&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="#000000" size="2" face="Courier New"&gt;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;table&lt;/font&gt; &lt;font color="#ff0000"&gt;class&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;style&amp;quot;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;tr&lt;/font&gt; &lt;font color="#ff0000"&gt;class&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;somestyle&amp;quot;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;td&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;SomeName1&lt;font color="#0000ff"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#800000"&gt;td&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;td&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;input&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;submit&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;value&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;Edit&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;class&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;btn&amp;quot;&lt;/font&gt; &lt;font color="#0000ff"&gt;/&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#800000"&gt;td&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#800000"&gt;tr&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;tr&lt;/font&gt; &lt;font color="#ff0000"&gt;class&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;gvAlternatingRowH35&amp;quot;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;td&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;SomeName2&lt;font color="#0000ff"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#800000"&gt;td&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;td&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;input&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;submit&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;value&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;Edit&amp;quot;&lt;/font&gt;&amp;#160;&lt;font color="#ff0000"&gt;class&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;btn&amp;quot;&lt;/font&gt; &lt;font color="#0000ff"&gt;/&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#800000"&gt;td&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#800000"&gt;tr&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&lt;font color="#0000ff"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#800000"&gt;table&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&lt;/font&gt; 
&lt;br /&gt;
&gt;&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
All the buttons have the same attributes.&amp;#160; If you want to click the “Edit” button
next to SomeName2, you can easily complete this task in selenium by using XPath and
its parent feature:
&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="#000000" size="2" face="Courier New"&gt;selenium.click(&lt;font color="#a31515"&gt;&amp;quot;//td[text()='SomeName2']/../td/input[@value='Edit']&amp;quot;&lt;/font&gt;)&lt;/font&gt; 
&lt;br /&gt;
&lt;br /&gt;
&gt;&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
As we mentioned above, this won’t be that easy to do with CSS because it doesn’t have
the appropriate feature. So, we used the JQuery parent() function to have the ability
to select the parent of the current node. It works really fast in all browsers, since
JQuery uses CSS.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
We added&amp;#160; Jquery’s library to the Selenium server (see steps 1 and 2 below) and
executed JQuery script directly from Selenium. To execute JQuery script, you can use &lt;strong&gt;selenium.getEval(someJS)&lt;/strong&gt; if
you need the return value, or &lt;strong&gt;selenium.runScript(someJS)&lt;/strong&gt; if you don’t. 
&lt;/p&gt;
&lt;p&gt;
But that was not enough for us. We wanted to select the parent element by using the
easy syntaxes of CSS locators. To use them, we had to add a new custom locator to
Selenium. Below, find the three easy steps that we took to add a custom locator. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;font size="3"&gt;1. Add Jquery’s library to Selenium server.&lt;/font&gt; &lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
Add JQuery’s library (‘jquery.min.js’) to your selenium-server.jar (‘selenium-server.jar\core\scripts\’
folder). To do that, open ‘selenium-server.jar’ by using one of the archives — for
example, 7-Zip — and drag-and-drop ‘jquery.min.js’ in the mentioned folder. 
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;font size="3"&gt;2. Add script reference to JQuery library.&lt;/font&gt; &lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
Add script reference to ‘jquery.min.js’ to the ‘&amp;lt;head&amp;gt;’ section of the RemoteRunner.html
(‘selenium-server.jar\core\’).
&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="#000000" size="2" face="Courier New"&gt;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;head&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
... 
&lt;br /&gt;
&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;script&lt;/font&gt; &lt;font color="#ff0000"&gt;language&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;JavaScript&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;text/javascript&amp;quot; &lt;/font&gt;&lt;font color="#ff0000"&gt;src&lt;/font&gt;&lt;font color="#0000ff"&gt;=&amp;quot;scripts/jquery.min.js&amp;quot;&lt;/font&gt; &lt;font color="#0000ff"&gt;/&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
... 
&lt;br /&gt;
&lt;font color="#0000ff"&gt;&amp;lt;\&lt;/font&gt;&lt;font color="#800000"&gt;head&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt; 
&lt;br /&gt;
&lt;/font&gt; 
&lt;br /&gt;
&gt;&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;&lt;font size="3"&gt;3. Add new JQuery locator to Selenium core.&lt;/font&gt;&lt;/strong&gt; 
&lt;/p&gt;
&lt;p&gt;
You can add a new JQuery locator to the Selenium core in the &lt;strong&gt;runSeleniumTest()&lt;/strong&gt; function
of the selenium-remoterunner.js file. All you need to do is to add a call of &lt;strong&gt;selenium.doAddLocationStrategy()&lt;/strong&gt; method
before Selenium property initialization of the window object. See the sample below
for more details. 
&lt;/p&gt;
&lt;blockquote&gt;&lt;code&gt;&lt;font color="#000000" size="2" face="Courier New"&gt;&lt;font color="#0000ff"&gt;function&lt;/font&gt; runSeleniumTest()
{ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; ... 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; selenium.doAddLocationStrategy(&amp;quot;jquery&amp;quot;, &amp;quot; 
&lt;br /&gt;
var loc = &lt;font color="#0000ff"&gt;locator&lt;/font&gt;; 
&lt;br /&gt;
var attr = &lt;font color="#0000ff"&gt;null&lt;/font&gt;; 
&lt;br /&gt;
var isattr = &lt;font color="#0000ff"&gt;false&lt;/font&gt;; 
&lt;br /&gt;
var inx = &lt;font color="#0000ff"&gt;locator&lt;/font&gt;.lastIndexOf(&lt;font color="#a31515"&gt;'@'&lt;/font&gt;); 
&lt;br /&gt;
&lt;br /&gt;
&lt;font color="#0000ff"&gt;if&lt;/font&gt; (inx != -1) { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; loc = &lt;font color="#0000ff"&gt;locator&lt;/font&gt;.&lt;font color="#0000ff"&gt;substring&lt;/font&gt;(0,
inx); 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; attr = &lt;font color="#0000ff"&gt;locator&lt;/font&gt;.&lt;font color="#0000ff"&gt;substring&lt;/font&gt;(inx
+ 1); 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; isattr = &lt;font color="#0000ff"&gt;true&lt;/font&gt; 
&lt;br /&gt;
} 
&lt;br /&gt;
&lt;br /&gt;
var selectors = loc.split(&lt;font color="#a31515"&gt;'&amp;lt;'&lt;/font&gt;); 
&lt;br /&gt;
var &lt;font color="#0000ff"&gt;found&lt;/font&gt; = $(inDocument); 
&lt;br /&gt;
&lt;br /&gt;
&lt;font color="#0000ff"&gt;for&lt;/font&gt; (var i = 0; i &amp;lt; selectors.length; i++) { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;if&lt;/font&gt; (i &amp;gt; 0) {&lt;font color="#0000ff"&gt;found&lt;/font&gt; =
$(&lt;font color="#0000ff"&gt;found&lt;/font&gt;.parents()[0]); 
&lt;br /&gt;
} 
&lt;br /&gt;
&lt;br /&gt;
&lt;font color="#0000ff"&gt;if&lt;/font&gt; (jQuery.&lt;font color="#0000ff"&gt;trim&lt;/font&gt;(selectors[i])
!= &lt;font color="#a31515"&gt;''&lt;/font&gt;) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;found&lt;/font&gt; = &lt;font color="#0000ff"&gt;found&lt;/font&gt;.find(selectors[i]); 
&lt;br /&gt;
} 
&lt;br /&gt;
&lt;br /&gt;
&lt;font color="#0000ff"&gt;if&lt;/font&gt; (&lt;font color="#0000ff"&gt;found&lt;/font&gt;.length &amp;gt; 0)
{ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;if&lt;/font&gt; (isattr) { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;return&lt;/font&gt; &lt;font color="#0000ff"&gt;found&lt;/font&gt;[0].getAttributeNode(attr); 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;else&lt;/font&gt; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;return&lt;/font&gt; &lt;font color="#0000ff"&gt;found&lt;/font&gt;[0]; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
} 
&lt;br /&gt;
&lt;font color="#0000ff"&gt;else&lt;/font&gt; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;return&lt;/font&gt; &lt;font color="#0000ff"&gt;null&lt;/font&gt;; 
&lt;br /&gt;
} 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;quot;); 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; ... 
&lt;br /&gt;
} 
&lt;br /&gt;
&lt;/font&gt; 
&lt;br /&gt;
&gt;&lt;/code&gt;&lt;/blockquote&gt; 
&lt;p&gt;
The first parameter of the &lt;strong&gt;selenium.doAddLocationStrategy&lt;/strong&gt; method
(“JQuery”) is the new Selenium locator’s name. The second one (“var loc = locator…”)
is the new custom Selenium locator. If you want to, you can write your own implementation
for the locator. To call the JQuery parent() function, we used the '&amp;lt;' custom symbol
.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
Finally, let’s take a look at how you can use the new JQuery locators, instead of
the XPath ones. 
&lt;/p&gt;
&lt;p&gt;
XPath locators: 
&lt;br /&gt;
•&amp;#160;&amp;#160;&amp;#160; xpath=//a[contains(@href,'#id1')] 
&lt;br /&gt;
•&amp;#160;&amp;#160;&amp;#160; xpath=(//table[@class='stylee'])//th[text()='theHeaderText']/../td 
&lt;br /&gt;
•&amp;#160;&amp;#160;&amp;#160; xpath=//input[@name='name2' and @value='yes'] 
&lt;/p&gt;
&lt;p&gt;
JQuery locators: 
&lt;br /&gt;
•&amp;#160;&amp;#160;&amp;#160; jquery= a[href*='#id1'] 
&lt;br /&gt;
•&amp;#160;&amp;#160;&amp;#160; jquery= table[class='stylee'] th:contains('theHeaderText')&amp;lt;td 
&lt;br /&gt;
•&amp;#160;&amp;#160;&amp;#160; jquery= input[name='name2'][value='yes'] 
&lt;/p&gt;
&lt;p&gt;
We hope you’ll find our experience useful to you. Also, we’d be happy to answer your
questions if you have any!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.muranosoft.com/Outsourcingblog/aggbug.ashx?id=6e91891a-20eb-4db1-8bd2-0342f82c4041" /&gt;</description>
      <comments>http://www.muranosoft.com/Outsourcingblog/CommentView,guid,6e91891a-20eb-4db1-8bd2-0342f82c4041.aspx</comments>
      <category>ASP.NET</category>
      <category>Quality Assurance</category>
      <category>Software Development</category>
    </item>
  </channel>
</rss>