Phlip | 12 Mar 2009 06:27
Picon
Gravatar

[TFUI] asserting HTML by example

extremists:

HTML is easy to test and hard to test well. A unit test must intercept and parse
it, hopefully _before_ it goes thru a web server.

I just wrote an assertion which turns that problem on its head. Instead of
asserting how to parse that HTML, we will assert how to build an example of HTML
that the production HTML must match.

This post is the high-level, language-agnostic, overview of these announcement
posts:

http://www.ruby-forum.com/topic/181145#792950

Here's the example:

user = users(:Moses)
get :edit_user, :id => user.id # fetches a web page

assert_xhtml do

form :action => '/users' do
fieldset do
legend 'Personal Information'
label 'First name'
input :type => 'text',
:name => 'user[first_name]'
:value => user.first_name
end
end

end

That's all. Inside the assertion's block, you declare the HTML you want, using a
Builder notation. (Nokogiri, in Ruby's case.)

The assertion skips over any intervening elements, such as <ul>, <table>, etc,
that the block did not build. In the above example, <fieldset> only needs to
appear somewhere inside the <form> - not necessarily its first element. But
those <label> and <input> fields must appear somewhere inside that <fieldset>,
and in the given order!

To create this assertion in your language, start with your nearest HTML builder.
Allow the user-programmer to build an example, then traverse its DOM, and
convert each item into an XPath seeking that item in the production HTML.
Declare a match if all the specified attributes match, and if most of the text
matches - disregarding blanks.

Then, for each match, recursively match each built child element, applying its
XPath relative to the current node in the production HTML's DOM.

When you find a fault, build an error message by rendering the current nodes to
HTML, and return this out of your loop statements. This Gist explicates the
algorithm:

http://gist.github.com/76136

The algorithm essentially matches two trees, depth-first and in-order. The
example HTML must be a subset of the production HTML.

If you survive all that recursing and matching then your assertion passes. You
verified a huge number of details, using extremely lean code, and you ignored
many more details, allowing them to change freely as you upgrade your website.

--
Phlip
http://www.zeroplayer.com/

__._,_.___
Recent Activity
    Visit Your Group
    Give Back

    Yahoo! for Good

    Get inspired

    by a good cause.

    Y! Toolbar

    Get it Free!

    easy 1-click access

    to your groups.

    Yahoo! Groups

    Start a group

    in 3 easy steps.

    Connect with others.

    .

    __,_._,___
    Jason Citron | 12 Mar 2009 06:33

    Re: [TFUI] asserting HTML by example

    For structural HTML testing you should check out assert_select. It comes
    with Rails 2.0.

    Useful for testing XML too.

    http://api.rubyonrails.org/classes/ActionController/Assertions/SelectorAssertions.html

    On Wed, Mar 11, 2009 at 10:27 PM, Phlip <phlip2005 <at> gmail.com> wrote:

    > extremists:
    >
    > HTML is easy to test and hard to test well. A unit test must intercept and
    > parse
    > it, hopefully _before_ it goes thru a web server.
    >
    > I just wrote an assertion which turns that problem on its head. Instead of
    > asserting how to parse that HTML, we will assert how to build an example of
    > HTML
    > that the production HTML must match.
    >
    > This post is the high-level, language-agnostic, overview of these
    > announcement
    > posts:
    >
    > http://www.ruby-forum.com/topic/181145#792950
    >
    > Here's the example:
    >
    > user = users(:Moses)
    > get :edit_user, :id => user.id # fetches a web page
    >
    > assert_xhtml do
    >
    > form :action => '/users' do
    > fieldset do
    > legend 'Personal Information'
    > label 'First name'
    > input :type => 'text',
    > :name => 'user[first_name]'
    > :value => user.first_name
    > end
    > end
    >
    > end
    >
    > That's all. Inside the assertion's block, you declare the HTML you want,
    > using a
    > Builder notation. (Nokogiri, in Ruby's case.)
    >
    > The assertion skips over any intervening elements, such as <ul>, <table>,
    > etc,
    > that the block did not build. In the above example, <fieldset> only needs
    > to
    > appear somewhere inside the <form> - not necessarily its first element. But
    >
    > those <label> and <input> fields must appear somewhere inside that
    > <fieldset>,
    > and in the given order!
    >
    > To create this assertion in your language, start with your nearest HTML
    > builder.
    > Allow the user-programmer to build an example, then traverse its DOM, and
    > convert each item into an XPath seeking that item in the production HTML.
    > Declare a match if all the specified attributes match, and if most of the
    > text
    > matches - disregarding blanks.
    >
    > Then, for each match, recursively match each built child element, applying
    > its
    > XPath relative to the current node in the production HTML's DOM.
    >
    > When you find a fault, build an error message by rendering the current
    > nodes to
    > HTML, and return this out of your loop statements. This Gist explicates the
    >
    > algorithm:
    >
    > http://gist.github.com/76136
    >
    > The algorithm essentially matches two trees, depth-first and in-order. The
    > example HTML must be a subset of the production HTML.
    >
    > If you survive all that recursing and matching then your assertion passes.
    > You
    > verified a huge number of details, using extremely lean code, and you
    > ignored
    > many more details, allowing them to change freely as you upgrade your
    > website.
    >
    > --
    > Phlip
    > http://www.zeroplayer.com/
    >
    >

    [Non-text portions of this message have been removed]

    __._,_.___
    Recent Activity
      Visit Your Group
      Give Back

      Yahoo! for Good

      Get inspired

      by a good cause.

      Y! Toolbar

      Get it Free!

      easy 1-click access

      to your groups.

      Yahoo! Groups

      Start a group

      in 3 easy steps.

      Connect with others.

      .

      __,_._,___
      Phlip | 12 Mar 2009 13:29
      Picon
      Gravatar

      Re: [TFUI] asserting HTML by example

      Jason Citron wrote:
      >
      > For structural HTML testing you should check out assert_select. It comes
      > with Rails 2.0.
      >
      > Useful for testing XML too.

      Try writing the equivalent of my assertion with it.

      I suspect you can't, because it can't constrain the element order.

      And the rest would be extremely verbose...

      --
      Phlip

      __._,_.___
      Recent Activity
        Visit Your Group
        Give Back

        Yahoo! for Good

        Get inspired

        by a good cause.

        Y! Toolbar

        Get it Free!

        easy 1-click access

        to your groups.

        Yahoo! Groups

        Start a group

        in 3 easy steps.

        Connect with others.

        .

        __,_._,___

        Gmane