Selenium and Section 508
Table columns should be headed by "th" tags to make the logical organization of data clear. Here the test is trivial:
<tr>Of course, this assumes proper HTML. If you are still using tables to do page layout (shame on the browser developers that force you to do this with their buggy CSS implementations!), the situation is more complex. In this case, I would suggest using a class attribute to distinguish non-layout tables (say, "class='layout'"). Then the solution is not too much worse:
<td>verifyXpathCount</td>
<td>//table[not(descendant::th)]</td>
<td>0</td>
</tr>
<tr>Of course, the second check ensures that there are no "th" elements (or "td" elements using the headers attribute) in purely layout tables, which might well confuse, especially with audio screen readers.
<td>verifyXpathCount</td>
<td>//table[not(@class='layout') and not(descendant::th)]</td>
<td>0</td>
</tr>
<tr>
<td>verifyXpathCount</td>
<td>//table[@class='layout' and (descendant::th or descendant::td/@headers)]</td>
<td>0</td>
</tr>
The scope attribute (equal to "col") or the headers attribute should be used for columns:
<tr>If you use layout tables, column groups, or what the HTML specification charmingly calls "axes in an n-dimensional space" (i.e., the axis attribute), the XPath will have to be adjusted, of course.
<td>verifyXpathCount</td>
<td>//table[descendant::th[normalize-space(@scope)!='col' and not(normalize-space(@headers))]]</td>
<td>0</td>
</tr>
The scope attribute (equal to "row") or headers attribute should also be used for the first cell in rows:
<tr>
<td>verifyXpathCount</td>
<td>//table[descendant::td[position()=1 and normalize-space(@scope)!='row' and not(normalize-space(@headers))]]</td>
<td>0</td>
</tr>
Labels
The
use of labels for various form data input fields is another important
aspect of the logical organization of information. The label for attribute must match up exactly with the id attribute of the field to which it refers:
<tr>
<td>verifyXpathCount</td>
<td>//input[not(//label/@for=./@id) and normalize-space(@type)!='hidden' and normalize-space(@type)!='button' and normalize-space(@type)!='submit' and normalize-space(@type)!='reset' and normalize-space(@type)!='image']</td>
<td>0</td>
</tr>
<tr>
<td>verifyXpathCount</td>
<td>//select[not(//label/@for=./@id)]</td>
<td>0</td>
</tr>
<tr>
<td>verifyXpathCount</td>
<td>//textarea[not(//label/@for=./@id)]</td>
<td>0</td>
</tr>
This can get a bit more complex with tables including checkboxes or radio buttons, which may legitimately not have labels.
Adding a class (possibly "radioTable") to the table and then adding
and not(normalize-space(@type)='radio' and ancestor::table[@class='radioTable'])
to the first of the above XPath expressions (just before the last square bracket) should help. You may, of course,
use another predicate to identify the table, such as an id or other attribute.
Frames
In
a perfect world, we wouldn't need frames at all, but in this fallen
one, they are sometimes useful. They should always have titles
describing their contents:
<tr>
<td>verifyXpathCount</td>
<td>//frame[not(normalize-space(@title))]</td>
<td>0</td>
</tr>
Image maps
Server-side image maps are rarely used nowadays and for good reason: they make it far more difficult for the user to determine whether or not they are in the right area of the image (the principle of least surprise applies here). They should not be used at all in Section-508-compliant websites unless equivalent text links are provided (which pretty much obviates the image map in the first place).
The test for them, however, is simple enough:
<tr>
<td>verifyXpathCount</td>
<td>//img[ancestor::a and @ismap]</td>
<td>0</td>
</tr>
<tr>
<td>verifyXpathCount</td>
<td>//input[normalize-space(@type)='image' and @ismap]</td>
<td>0</td>
</tr>
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)





Comments
Mostly Harmless replied on Thu, 2009/01/01 - 6:07pm