[TFUI] Re: XPath to test HTML

Phlip <[email protected]> Thu, 25 Sep 2008 03:38:56 -0700
Newsgroups gmane.comp.programming.test-first-user-interfaces
Message-ID <[email protected]>
--83Ahxee9nUOIcYUAawZwhjTO4MtRHsU3goWPCXe
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

George Dinwiddie wrote:

> Phlip wrote:

>> I thought the industry would support more XPath testing by now. What libraries 
>> are out there (besides mine?)?

> HtmlUnit, for one.  You won't like it, though, as it's written in Java.

That wouldn't be very politic of me!

Here's the first hit:

http://www.google.com/codesearch?q=package%3Ahtmlunit+xpath

htmlunit-plugin-0.3-src/.../plugin/htmlunit/HtmlUnitFunctionTagTest.java

     75:   functionTag.navigate("file:./tst/html/tables.html");
           String xpath = "//head[title='tables page']";
           functionTag.assertXPathMatches(xpath);

     85:   MockHtmlUnitHelper helper = setMockHelper();
           String xpath = "//head[title='tables page']";
           functionTag.clickElementWithXPath(xpath);

Firstly, where did the @ go? That should be @title = 'tables page' in the predicate.

Next, I want to nest them. Suppose we have a report table which must contain a 
certain HD. I want this:

   assert_xpath :table, :report do  #  hits //table[@id='report']
     assert_xpath 'tbody/tr/td[ . = "SubTotal" ]'
   end

The do-end lets us avoid writing a run-on XPath expression. And if the inner 
assert_xpath fails, its error diagnostic will only print out its current context 
- the outer <table> - not the whole page.

Then you can stack up more assertions inside the block. The goal is not to 
mirror your HTML in the tests, but to efficiently skip over the fuzzy details 
that might change.

-- 
   Phlip

--83Ahxee9nUOIcYUAawZwhjTO4MtRHsU3goWPCXe
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
</head>




<body style="background-color: #ffffff;">

<!--~-|**|PrettyHtmlStartT|**|-~-->
<div id="ygrp-mlmsg" style="width:655px; position:relative;">
<div id="ygrp-msg" style="width: 470px; margin:0; padding:0 25px 0 0; float:left; z-index:1;">
<!--~-|**|PrettyHtmlEndT|**|-~-->

    <div id="ygrp-text">
            <p>George Dinwiddie wrote:<br>
<br>
&gt; Phlip wrote:<br>
<br>
&gt;&gt; I thought the industry would support more XPath testing by now. What libraries <br>
&gt;&gt; are out there (besides mine?)?<br>
<br>
&gt; HtmlUnit, for one.  You won't like it, though, as it's written in Java.<br>
<br>
That wouldn't be very politic of me!<br>
<br>
Here's the first hit:<br>
<br>
<a href="http://www.google.com/codesearch?q=package%3Ahtmlunit+xpath">http://www.google.<wbr>com/codesearch?<wbr>q=package%<wbr>3Ahtmlunit&#43;<wbr>xpath</a><br>
<br>
htmlunit-plugin-<wbr>0.3-src/.<wbr>../plugin/<wbr>htmlunit/<wbr>HtmlUnitFunction<wbr>TagTest.java<br>
<br>
75:   functionTag.<wbr>navigate(<wbr>&quot;file:./tst/<wbr>html/tables.<wbr>html&quot;);<br>
           String xpath = &quot;//head[title=<wbr>'tables page']&quot;;<br>
           functionTag.<wbr>assertXPathMatch<wbr>es(xpath)<wbr>;<br>
<br>
85:   MockHtmlUnitHelper helper = setMockHelper(<wbr>);<br>
           String xpath = &quot;//head[title=<wbr>'tables page']&quot;;<br>
           functionTag.<wbr>clickElementWith<wbr>XPath(xpath)<wbr>;<br>
<br>
Firstly, where did the @ go? That should be @title = 'tables page' in the predicate.<br>
<br>
Next, I want to nest them. Suppose we have a report table which must contain a <br>
certain HD. I want this:<br>
<br>
assert_xpath :table, :report do  #  hits //table[@id=<wbr>'report']<br>
     assert_xpath 'tbody/tr/td[ . = &quot;SubTotal&quot; ]'<br>
   end<br>
<br>
The do-end lets us avoid writing a run-on XPath expression. And if the inner <br>
assert_xpath fails, its error diagnostic will only print out its current context <br>
- the outer &lt;table&gt; - not the whole page.<br>
<br>
Then you can stack up more assertions inside the block. The goal is not to <br>
mirror your HTML in the tests, but to efficiently skip over the fuzzy details <br>
that might change.<br>
<br>
-- <br>
   Phlip<br>
</p>
    </div>  

    <!--~-|**|PrettyHtmlStart|**|-~-->
    <span width="1" style="color: white;">__._,_.___</span>
    <!-- Start the section with Message In topic -->
    <div id="ygrp-actbar">
              <span class="left">
          <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/message/1018;_ylc=X3oDMTM0cGNuMDNnBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BG1zZ0lkAzEwMTgEc2VjA2Z0cgRzbGsDdnRwYwRzdGltZQMxMjIyMzM5MTQxBHRwY0lkAzEwMTg-">
            Messages in this topic          </a> (<span class="bld">1</span>)
        </span>
        <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/post;_ylc=X3oDMTJwY3U1amJlBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BG1zZ0lkAzEwMTgEc2VjA2Z0cgRzbGsDcnBseQRzdGltZQMxMjIyMzM5MTQx?act=reply&messageNum=1018">
          <span class="bld">
            Reply          </span> (via web post)
        </a>  | 
        <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/post;_ylc=X3oDMTJlbmtrZHJiBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA250cGMEc3RpbWUDMTIyMjMzOTE0MQ--" class="bld">
          Start a new topic        </a>
          </div> 
    <!-------     Start Nav Bar  ------>
    <!-- |**|begin egp html banner|**| -->
    <div id="ygrp-vitnav">
                <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/messages;_ylc=X3oDMTJlMDd0Z2RpBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA21zZ3MEc3RpbWUDMTIyMjMzOTE0MQ--">Messages</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/files;_ylc=X3oDMTJmZjNya2NrBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2ZpbGVzBHN0aW1lAzEyMjIzMzkxNDE-">Files</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/photos;_ylc=X3oDMTJlNWI3MmRlBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA3Bob3QEc3RpbWUDMTIyMjMzOTE0MQ--">Photos</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/links;_ylc=X3oDMTJmam5pY2xnBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2xpbmtzBHN0aW1lAzEyMjIzMzkxNDE-">Links</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/database;_ylc=X3oDMTJjNHZ1OGZjBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2RiBHN0aW1lAzEyMjIzMzkxNDE-">Database</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/polls;_ylc=X3oDMTJmczgwc2c4BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA3BvbGxzBHN0aW1lAzEyMjIzMzkxNDE-">Polls</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/members;_ylc=X3oDMTJlZGFlZGdnBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA21icnMEc3RpbWUDMTIyMjMzOTE0MQ--">Members</a>  
            |    <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/calendar;_ylc=X3oDMTJkNmx2Y210BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2NhbARzdGltZQMxMjIyMzM5MTQx">Calendar</a>  
    </div>  
    <!-- |**|end egp html banner|**| -->

                <div id="ygrp-grft">
                  

              </div>
    
    <!-- yahoo logo -->
    <!-- |**|begin egp html banner|**| -->
    <div id="ygrp-ft">
      <a href="http://groups.yahoo.com/;_ylc=X3oDMTJkcjEwaTdmBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2dmcARzdGltZQMxMjIyMzM5MTQx">
      <img src="http://us.i1.yimg.com/us.yimg.com/i/yg/img/logo/ma_grp_160.gif" height="15" width="106" border="0" alt="Yahoo! Groups"></a> <br>
      <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces/join;_ylc=X3oDMTJmdGtlZzE0BF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA3N0bmdzBHN0aW1lAzEyMjIzMzkxNDE-">Change settings via the Web</a> (Yahoo! ID required) <br>
      Change settings via email: <a href="mailto:TestFirstUserInterfaces-digest-hHKSG33TihhbjbujkaE4pw@public.gmane.org?subject=Email Delivery: Digest">Switch delivery to Daily Digest</a> | <a href = "mailto:TestFirstUserInterfaces-traditional-hHKSG33TihhbjbujkaE4pw@public.gmane.org?subject=Change Delivery Format: Traditional">Switch format to Traditional</a> <br>

      <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces;_ylc=X3oDMTJkNmZrb2JuBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwNmdHIEc2xrA2hwZgRzdGltZQMxMjIyMzM5MTQx">
        Visit Your Group 
      </a> |
      <a href="http://docs.yahoo.com/info/terms/">
        Yahoo! Groups Terms of Use      </a> |
      <a href="mailto:TestFirstUserInterfaces-unsubscribe-hHKSG33TihhbjbujkaE4pw@public.gmane.org?subject=">
        Unsubscribe      </a> 
    </div>     <!-- |**|end egp html banner|**| -->
  </div> <!-- ygrp-msg -->

  
  <!-- Sponsor -->
  <!-- |**|begin egp html banner|**| -->
  <div id="ygrp-sponsor" style="width:160px; float:right; clear:none; margin:0 0 25px 0; background:white;">
    <!-- Network content -->
    
<!-- Start Recommendations -->
<div id="ygrp-reco">
     </div>
<!-- End Recommendations -->

	    <!-- Start vitality -->
	    <div id="ygrp-vital">
	      	      <a href="http://groups.yahoo.com/group/TestFirstUserInterfaces;_ylc=X3oDMTJlbTdqNzZyBF9TAzk3MzU5NzE0BGdycElkAzg3NDQ3MDQEZ3Jwc3BJZAMxNzA1MDA3MjA3BHNlYwN2dGwEc2xrA3ZnaHAEc3RpbWUDMTIyMjMzOTE0MQ--">
		Visit Your Group	      </a>
	    </div> 
	    	    	      
	    <!-- Network content -->
	    	          <div id="nc">
              <div class="ad">
                      <div id="hd1">Yahoo! Finance</div> 
<p><a href="http://us.ard.yahoo.com/SIG=13o3g04o2/M=493064.12016257.12445664.8674578/D=groups/S=1705007207:NC/Y=YAHOO/EXP=1222346341/L=/B=cvaGDULaX.c-/J=1222339141750884/A=4507179/R=0/SIG=12de4rskk/*http://us.rd.yahoo.com/evt=50284/*http://finance.yahoo.com/personal-finance">It's Now Personal</a></p> 
<p>Guides, news,</p> 
<p>advice & more.</p>                   </div>
                    <div class="ad">
                      <div id="hd1">Curves on Yahoo!</div> 
<p><a href="http://us.ard.yahoo.com/SIG=13p29ru7i/M=493064.12016299.12445691.11322765/D=groups/S=1705007207:NC/Y=YAHOO/EXP=1222346341/L=/B=c_aGDULaX.c-/J=1222339141750884/A=4990221/R=0/SIG=11odsb6gn/*http://new.groups.yahoo.com/Women_Of_Curves_Everywhere">A group for women</a></p> 
<p>to share &amp; discuss</p> 
<p>food &amp; weight loss.</p>                  </div>
                    <div class="ad">
                      <div id="hd1">All-Bran</div> 
<p><a href="http://us.ard.yahoo.com/SIG=13o8eu8jm/M=493064.12016283.12445687.8674578/D=groups/S=1705007207:NC/Y=YAHOO/EXP=1222346341/L=/B=dPaGDULaX.c-/J=1222339141750884/A=5202317/R=0/SIG=11aijbghb/*http://new.groups.yahoo.com/allbrangroup">Day 10 Club</a></p> 
<p>on Yahoo! Groups</p> 
<p>Feel better with fiber.</p>                  </div>
          </div>
	    
	  </div> 	  <!-- |**|end egp html banner|**| -->
	  <div style="clear:both; color: #FFF; font-size:1px;">.</div>
	</div> 		  <img src="http://geo.yahoo.com/serv?s=97359714/grpId=8744704/grpspId=1705007207/msgId=1018/stime=1222339141/nc1=4507179/nc2=4990221/nc3=5202317" width="1" height="1"> <br>
	
	<span  style="color: white;">__,_._,___</span>
	<!--~-|**|PrettyHtmlEnd|**|-~-->
	</body>
	<!--~-|**|PrettyHtmlStart|**|-~-->
	<head>
<style type="text/css">
<!--
#ygrp-mkp{
  border: 1px solid #d8d8d8;
  font-family: Arial;
  margin: 14px 0px;
  padding: 0px 14px;
}
#ygrp-mkp hr{
  border: 1px solid #d8d8d8;
}
#ygrp-mkp #hd{
  color: #628c2a;
  font-size: 85%;
  font-weight: bold;
  line-height: 122%;
  margin: 10px 0px;
}
#ygrp-mkp #ads{
  margin-bottom: 10px;
}
#ygrp-mkp .ad{
  padding: 0 0;
}
#ygrp-mkp .ad a{
  color: #0000ff;
  text-decoration: none;
}
-->
</style>
</head>
	<head>
<style type="text/css">
<!--
#ygrp-sponsor #ygrp-lc{
  font-family: Arial;
}
#ygrp-sponsor #ygrp-lc #hd{
  margin: 10px 0px;
  font-weight: bold;
  font-size: 78%;
  line-height: 122%;
}
#ygrp-sponsor #ygrp-lc .ad{
  margin-bottom: 10px;
  padding: 0 0;
}
-->
</style>
</head>
	<head>
	<style type="text/css">
	<!--
	#ygrp-mlmsg {font-size:13px; font-family: arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}
	#ygrp-mlmsg table {font-size:inherit;font:100%;}
	#ygrp-mlmsg select, input, textarea {font:99% arial,helvetica,clean,sans-serif;}
	#ygrp-mlmsg pre, code {font:115% monospace;*font-size:100%;}
	#ygrp-mlmsg * {line-height:1.22em;}
	#ygrp-text{
	    font-family: Georgia;	
	}
	#ygrp-text p{
	    margin: 0 0 1em 0;
	}
	#ygrp-tpmsgs{
	    font-family: Arial;	
	    clear: both;
	}
	#ygrp-vitnav{
		padding-top: 10px;
		font-family: Verdana;
		font-size: 77%;
		margin: 0;
	}
	#ygrp-vitnav a{
		padding: 0 1px;
	}
	#ygrp-actbar{
		clear: both;
		margin: 25px 0;
		white-space:nowrap;
		color: #666;
		text-align: right;
	}
	#ygrp-actbar .left{
		float: left;
		white-space:nowrap;
	}
	.bld{font-weight:bold;}
	#ygrp-grft{
		font-family: Verdana;
		font-size: 77%;
		padding: 15px 0;
	}
	#ygrp-ft{
	  font-family: verdana;
	  font-size: 77%;
	  border-top: 1px solid #666; 
	  padding: 5px 0; 
	}
	#ygrp-mlmsg #logo{
	  padding-bottom: 10px;
	}

	#ygrp-reco {
	margin-bottom: 20px;
	padding: 0px;
	}
	#ygrp-reco #reco-head {
		font-weight: bold;
		color: #ff7900;
	}

	#reco-grpname{
        font-weight: bold;
        margin-top: 10px;
  	}
	#reco-category{
        	font-size: 77%;
	}
	#reco-desc{
        	font-size: 77%;
	}

	#ygrp-vital{
		background-color: #e0ecee;
		margin-bottom: 20px;
		padding: 2px 0 8px 8px;
	}
	#ygrp-vital #vithd{
		font-size: 77%;
		font-family: Verdana;
		font-weight: bold;
		color: #333;
		text-transform: uppercase;
	}
	#ygrp-vital ul{
		padding: 0;
		margin: 2px 0;
	}
	#ygrp-vital ul li{
	  list-style-type: none;
	  clear: both;
	  border: 1px solid #e0ecee;  
	}
	#ygrp-vital ul li .ct{
	  font-weight: bold;
	  color: #ff7900;
	  float: right;
	  width: 2em;
	  text-align:right;
	  padding-right: .5em;
	}
	#ygrp-vital ul li .cat{
	  font-weight: bold;
	}
	#ygrp-vital a{
		text-decoration: none;
	}

	#ygrp-vital a:hover{
	  text-decoration: underline;
	}

	#ygrp-sponsor #hd{
		color: #999;
		font-size: 77%;
	}
	#ygrp-sponsor #ov{
		padding: 6px 13px;
		background-color: #e0ecee;
		margin-bottom: 20px;
	}
	#ygrp-sponsor #ov ul{
		padding: 0 0 0 8px;
		margin: 0;
	}
	#ygrp-sponsor #ov li{
		list-style-type: square;
		padding: 6px 0;
		font-size: 77%;
	}
	#ygrp-sponsor #ov li a{
		text-decoration: none;
		font-size: 130%;
	}
	#ygrp-sponsor #nc{
	  background-color: #eee;
	  margin-bottom: 20px;
	  padding: 0 8px;
	}
	#ygrp-sponsor .ad{
		padding: 8px 0;
	}
	#ygrp-sponsor .ad #hd1{
		font-family: Arial;
		font-weight: bold;
		color: #628c2a;
		font-size: 100%;
		line-height: 122%;
	}
	#ygrp-sponsor .ad a{
		text-decoration: none;
	}
	#ygrp-sponsor .ad a:hover{
		text-decoration: underline;
	}
	#ygrp-sponsor .ad p{
		margin: 0;
	}
	o{font-size: 0; }
	.MsoNormal{
	   margin: 0 0 0 0;
	}
	#ygrp-text tt{
	  font-size: 120%;
	}
	blockquote{margin: 0 0 0 4px;}
	.replbq{margin:4}
	-->
	</style>
	</head>
	<!--~-|**|PrettyHtmlEnd|**|-~-->
	</html><!--End group email -->


--83Ahxee9nUOIcYUAawZwhjTO4MtRHsU3goWPCXe--