David Sills's muse is fueled by Bach, Beethoven, and Brahms (and Berlioz and Boulez). He has no life, which comports well with the über-geekitude to which he aspires. He reads and writes fitfully in English, Spanish, French, German, Italian (mostly medieval), C, VB, Perl.... Oh, and Java and XSLT, lots and lots of Java and XSLT. Trained somewhere in darkest Central America, he works today at DataSource, Inc., on the product team for the CASE tool Abri. David has posted 9 posts at DZone. View Full User Profile

Selenium and Section 508

01.01.2009
| 18907 views |
  • submit to reddit
Tables

Table columns should be headed by "th" tags to make the logical organization of data clear. Here the test is trivial:

  <tr>
<td>verifyXpathCount</td>
<td>//table[not(descendant::th)]</td>
<td>0</td>
</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:
  <tr>
<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>
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.
The scope attribute (equal to "col") or the headers attribute should be used for columns:
  <tr>
<td>verifyXpathCount</td>
<td>//table[descendant::th[normalize-space(@scope)!='col' and not(normalize-space(@headers))]]</td>
<td>0</td>
</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.
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>

Published at DZone with permission of its author, David Sills.

(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

It is still ridiculous to me that Selenium uses an HTML file with tables rather than a proper XML file. In 2003 or 4 a friend and I sent them a patch to support XML. They passed on it. Too bad.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.