Wincent Colaiuta
2007-May-21 21:18 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
When writing view specs is there any way to test not only for the presence of tags (have_tag) and nested tags (with_tag), but also test that they appear in a given order? For example, consider the following: it ''should display the login names, display names and email address in alternating rows'' do response.should have_tag(''div.odd>div'') do with_tag(''div'', ''example login name 1'') with_tag(''div'', ''example display name 1'') with_tag(''div'', ''example email address 1'') end response.should have_tag(''div.even>div'') do with_tag(''div'', ''example login name 2'') with_tag(''div'', ''example display name 2'') with_tag(''div'', ''example email address 2'') end end I can change the order of the have_tag blocks and I can also change the order of the with_tag calls within each block without breaking the specs. Or to put it alternatively, my view can render the "odd" and "even" divs in a different order, or the nested divs inside each, without breaking the specs. In many cases, this might not matter. But what if I want to test for alternating divs (odd, even, odd even)? I can add multiple have_tag assertions but their order won''t be considered, so I''m not really testing the alternation, only for existence. Cheers, Wincent
David Chelimsky
2007-May-22 00:01 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
On 5/21/07, Wincent Colaiuta <win at wincent.com> wrote:> When writing view specs is there any way to test not only for the > presence of tags (have_tag) and nested tags (with_tag), but also test > that they appear in a given order? > > For example, consider the following: > > it ''should display the login names, display names and email > address in alternating rows'' do > response.should have_tag(''div.odd>div'') do > with_tag(''div'', ''example login name 1'') > with_tag(''div'', ''example display name 1'') > with_tag(''div'', ''example email address 1'') > end > response.should have_tag(''div.even>div'') do > with_tag(''div'', ''example login name 2'') > with_tag(''div'', ''example display name 2'') > with_tag(''div'', ''example email address 2'') > end > end > > I can change the order of the have_tag blocks and I can also change > the order of the with_tag calls within each block without breaking > the specs. Or to put it alternatively, my view can render the "odd" > and "even" divs in a different order, or the nested divs inside each, > without breaking the specs. > > In many cases, this might not matter. But what if I want to test for > alternating divs (odd, even, odd even)? I can add multiple have_tag > assertions but their order won''t be considered, so I''m not really > testing the alternation, only for existence.Not to pass the buck ... but I''m going to pass the buck on this one. have_tag and with_tag wrap assert_select, which ships with Rails. I''ve actually submitted a couple of patches to assert_select to Rails myself because I''d like to see better error messages and more rjs coverage. I''d encourage you to make this request and/or submit a patch to Rails directly as well. David> > Cheers, > Wincent > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Wincent Colaiuta
2007-May-22 00:16 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
El 22/5/2007, a las 2:01, David Chelimsky escribi?:> Not to pass the buck ... but I''m going to pass the buck on this one. > have_tag and with_tag wrap assert_select, which ships with Rails. I''ve > actually submitted a couple of patches to assert_select to Rails > myself because I''d like to see better error messages and more rjs > coverage. I''d encourage you to make this request and/or submit a patch > to Rails directly as well.Ok, thanks for the advice, David. I''ve submitted a request ticket: http://dev.rubyonrails.org/ticket/8428 If you have any insight onto what such a patch might involve, please let me know. I don''t know enough about Rails internals to work something up yet, but perhaps with some help I might be able to get at least a basic prototype working at some point. Cheers, Wincent
David Chelimsky
2007-May-22 00:27 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
On 5/21/07, Wincent Colaiuta <win at wincent.com> wrote:> El 22/5/2007, a las 2:01, David Chelimsky escribi?: > > > Not to pass the buck ... but I''m going to pass the buck on this one. > > have_tag and with_tag wrap assert_select, which ships with Rails. I''ve > > actually submitted a couple of patches to assert_select to Rails > > myself because I''d like to see better error messages and more rjs > > coverage. I''d encourage you to make this request and/or submit a patch > > to Rails directly as well. > > Ok, thanks for the advice, David. I''ve submitted a request ticket: > > http://dev.rubyonrails.org/ticket/8428 > > If you have any insight onto what such a patch might involve, please > let me know. I don''t know enough about Rails internals to work > something up yet, but perhaps with some help I might be able to get > at least a basic prototype working at some point.You don''t have to know too much about Rails internals. assert_select is nicely decoupled from most of it. You will have to put on your regexp fu. Take a look at actionpack/test/controller/selector_assertions.rb and actionpack/lib/action_controller/assertions/selector_assertions.rb. Cheers, David> > Cheers, > Wincent > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Wincent Colaiuta
2007-May-22 11:48 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
El 22/5/2007, a las 2:27, David Chelimsky escribi?:> You don''t have to know too much about Rails internals. assert_select > is nicely decoupled from most of it. You will have to put on your > regexp fu. > > Take a look at actionpack/test/controller/selector_assertions.rb and > actionpack/lib/action_controller/assertions/selector_assertions.rb.Ok, I''ve had a look at the both the Rails code in actionpack/lib/ action_controller/assertions/selector_assertions.rb and the RSpec implementations of have_tag and with_tag in lib/spec/rails/matchers/ assert_select.rb (actionpack/test/controller/selector_assertions.rb doesn''t exist in either Rails 1.2.3 or trunk; did you mean actionpack/ test/controller/assert_select_test?). I don''t necessarily have it fully grokked yet, but my observations of the RSpec side of things thus far are: 1. Each time you invoke "have_tag" you create a new AssertSelect instance under the covers 2. "with_tag" invokes "have_tag" behind the scenes, so that means a new AssertSelect instance gets created there two 3. I presume the method that ends up getting called when you do "should have_tag" is AssertSelect#matches? 4. If and only if the response text is a String, AssertSelect#matches? creates a new HTML::Document instance from it and prepends it to the arguments list 5. Finally, AssertSelect#matches? sends an "assert_select" message to the @spec_scope (which is really "self", ie. the matcher). So that''s the way things are by the time Rails receives the message. Observations on the Rails side: 1. It appears that assert_select and friends are included into the object being tested via actionpack/lib/action_controller/assertions.rb. 2. assert_select uses an instance variable, @selected, to allow nesting of assert_select; so perhaps using instance variables may be the way to preserve state between assert_select calls and track the ordering of the elements. The only problem is, as I said I haven''t fully grokked this yet so I am not sure what the lifetime of the objects in question are and how long the instance variables will stick around. It seems that a new AssertSelect instance is created for every assertion, every assertion has its own matcher, and the matcher receives the assert_select message, so I am not sure how to achieve the kind of inter-matcher or inter-assertion dependency which would allow ordering comparisons to be made. In other words, I don''t know if this can be tackled purely from the Rails side of things. One thing which may prove useful is that assert_select returns an array of matches, and also passes that array into any block (if called with a block). The array contains HTML::Node instances, and these nodes have a position attribute (the position of the node within the byte stream); so making comparisons of order externally is possible and could be down already right now with no changes (although not transparently; you''d have to explicitly compare element positions in your specs). There are two more questions that grow out of this: 1. What would be the ideal "scope" for these order restrictions to take effect? Should multiple have_tag calls within the same example (the same "it" block) be expected to appear in order? Or should it apply to have_tags calls within the same context (the same "describe" block)? Should calling "render" again have the effect of "resetting" things? 2. If this can be implemented, should it apply as a default (might break existing specs), or should it be made optional (pass an additional parameter to indicate that ordering is important?); an alternative would be to add two additional methods, have_tags and with_tags, which would expect an array of selectors rather than a single selector, and would expect them to succeed in order (I almost think that this is the best solution). Any ideas? Cheers, Wincent
Wincent Colaiuta
2007-May-24 13:25 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
Ok, following up on my posts from a couple of days ago... The question:> When writing view specs is there any way to test not only for the > presence of tags (have_tag) and nested tags (with_tag), but also test > that they appear in a given order?The workaround:> One thing which may prove useful is that > assert_select returns an array of matches, and also passes that array > into any block (if called with a block). The array contains > HTML::Node instances, and these nodes have a position attribute (the > position of the node within the byte stream); so making comparisons > of order externally is possible and could be down already right now > with no changes (although not transparently; you''d have to explicitly > compare element positions in your specs).Here''s an example spec showing one way this could be done. It''s pretty ugly though (and I expect the list server will make it even uglier by hard-wrapping it) as it requires quite a bit of "book- keeping" to be done: describe ''/users/index with 2 users'' do before do users = (1..2).inject([]) do |list, index| user = mock("user #{index}") user.should_receive(:login_name).and_return("example login name #{index}") user.should_receive(:display_name).and_return("example display name #{index}") user.should_receive(:email_address).and_return("example email address #{index}") list << user end assigns[:users] = users render ''users/index'' end it ''should display the login names, displays names and email address, in alternating odd and even rows'' do odd = even = nil response.should have_tag(''div.odd>div'') do |match| odd = match[0] positions = [] with_tag(''div.label'', ''Login name:'') { |match| positions << match[0].position } with_tag(''div.info'', ''example login name 1'') { |match| positions << match[0].position } with_tag(''div.label'', ''Display name:'') { |match| positions << match[0].position } with_tag(''div.info'', ''example display name 1'') { |match| positions << match[0].position } with_tag(''div.label'', ''Email address:'') { |match| positions << match[0].position } with_tag(''div.info'', ''example email address 1'') { |match| positions << match[0].position } positions.should == positions.sort end response.should have_tag(''div.even>div'') do |match| even = match[0] positions = [] with_tag(''div.label'', ''Login name:'') { |match| positions << match[0].position } with_tag(''div.info'', ''example login name 2'') { |match| positions << match[0].position } with_tag(''div.label'', ''Display name:'') { |match| positions << match[0].position } with_tag(''div.info'', ''example display name 2'') { |match| positions << match[0].position } with_tag(''div.label'', ''Email address:'') { |match| positions << match[0].position } with_tag(''div.info'', ''example email address 2'') { |match| positions << match[0].position } positions.should == positions.sort end odd.position.should < even.position end end Compare this to the version without the book-keeping: describe ''/users/index with 2 users'' do before do users = (1..2).inject([]) do |list, index| user = mock("user #{index}") user.should_receive(:login_name).and_return("example login name #{index}") user.should_receive(:display_name).and_return("example display name #{index}") user.should_receive(:email_address).and_return("example email address #{index}") list << user end assigns[:users] = users render ''users/index'' end it ''should display the login names, displays names and email address, in alternating odd and even rows'' do response.should have_tag(''div.odd>div'') do with_tag(''div.label'', ''Login name:'') with_tag(''div.info'', ''example login name 1'') with_tag(''div.label'', ''Display name:'') with_tag(''div.info'', ''example display name 1'') with_tag(''div.label'', ''Email address:'') with_tag(''div.info'', ''example email address 1'') end response.should have_tag(''div.even>div'') do with_tag(''div.label'', ''Login name:'') with_tag(''div.info'', ''example login name 2'') with_tag(''div.label'', ''Display name:'') with_tag(''div.info'', ''example display name 2'') with_tag(''div.label'', ''Email address:'') with_tag(''div.info'', ''example email address 2'') end end end So, yes, the book-keeping-free version is much easier to look at, but it''s also far too easy for the spec to pass with faulty input (jumble the divs around in any order you want and it will still pass). So improving have_tag, with_tag, or the underlying assert_select seems to be a very worthwhile project; I''ve got a very basic prototype implementation in place based on this small patch to actionpack/lib/ action_controller/assertions/selector_assertions.rb: === vendor/rails/actionpack/lib/action_controller/assertions/ selector_assertions.rb =================================================================--- vendor/rails/actionpack/lib/action_controller/assertions/ selector_assertions.rb (revision 7191) +++ vendor/rails/actionpack/lib/action_controller/assertions/ selector_assertions.rb (local) @@ -286,6 +286,13 @@ "Expected at most #{equals[:maximum]} elements, found # {matches.size}." end + if !matches.empty? + if @previous_match and matches[0].position < @previous_match.position + raise "selector order mismatch (''#{matches[0].to_s}'' at position #{matches[0].position} appears before ''# {@previous_match.to_s}'' at position #{@previous_match.position})" + end + @previous_match = matches[0] + end + # If a block is given call that block. Set @selected to allow # nested assert_select, which can be nested several levels deep. if block_given? && !matches.empty? Experimentation shows that the dynamic class created by RSpec for each "it" block receives the assert_select messages and hangs around for the duration of the block. So that means instance variables can be used to store positional information and an exception can be thrown if things don''t happen in the expected order. This works, at least for the sample spec I''ve posted above. In the event of the ordering requirement failing the exception will include diagnostic information that looks like this: selector order mismatch (''<div class="label">Display name:</div>'' at position 109 appears before ''<div class="info">example login name 1</ div>'' at position 150) Limitations, and doubts: - I don''t know what type of exception to throw, so for now I''m just throwing a String (which becomes a RuntimeError) - no way to make it optional at this stage - this patch (or anything like it) is unlikely to get accepted in Rails because it will probably break lots of existing specs/tests which are written without caring about selector ordering Any further ideas? Cheers, Wincent
Matt Deiters
2007-May-24 14:24 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
Hey Wincent, A couple of questions/comments. Are you doing some sorting logic in the view? If so I can see why you would want to assert order, but perhaps it would be better to move that type of logic out of view and into your controller (or perhaps a presenter or helper). Then you would test the order of your collection in one of those (helper/controller) types of specs. Then your view would just iterate of the collection and if your view is just iterating over the collection, then when your testing order you would really be testing does ''ruby iterate right'', which again is something we don''t want to test in our views (or need test at all). Matt Deiters>From: Wincent Colaiuta <win at wincent.com> >Reply-To: rspec-users <rspec-users at rubyforge.org> >To: rspec-users <rspec-users at rubyforge.org> >Subject: Re: [rspec-users] Ordering in view specs using have_tag and >with_tag >Date: Thu, 24 May 2007 15:25:26 +0200 > >Ok, following up on my posts from a couple of days ago... > >The question: > > > When writing view specs is there any way to test not only for the > > presence of tags (have_tag) and nested tags (with_tag), but also test > > that they appear in a given order? > >The workaround: > > > One thing which may prove useful is that > > assert_select returns an array of matches, and also passes that array > > into any block (if called with a block). The array contains > > HTML::Node instances, and these nodes have a position attribute (the > > position of the node within the byte stream); so making comparisons > > of order externally is possible and could be down already right now > > with no changes (although not transparently; you''d have to explicitly > > compare element positions in your specs). > >Here''s an example spec showing one way this could be done. It''s >pretty ugly though (and I expect the list server will make it even >uglier by hard-wrapping it) as it requires quite a bit of "book- >keeping" to be done: > >describe ''/users/index with 2 users'' do > before do > users = (1..2).inject([]) do |list, index| > user = mock("user #{index}") > user.should_receive(:login_name).and_return("example login >name #{index}") > user.should_receive(:display_name).and_return("example display >name #{index}") > user.should_receive(:email_address).and_return("example email >address #{index}") > list << user > end > assigns[:users] = users > render ''users/index'' > end > > it ''should display the login names, displays names and email >address, in alternating odd and even rows'' do > odd = even = nil > response.should have_tag(''div.odd>div'') do |match| > odd = match[0] > positions = [] > with_tag(''div.label'', ''Login name:'') { |match| >positions << match[0].position } > with_tag(''div.info'', ''example login name 1'') { |match| >positions << match[0].position } > with_tag(''div.label'', ''Display name:'') { |match| >positions << match[0].position } > with_tag(''div.info'', ''example display name 1'') { |match| >positions << match[0].position } > with_tag(''div.label'', ''Email address:'') { |match| >positions << match[0].position } > with_tag(''div.info'', ''example email address 1'') { |match| >positions << match[0].position } > positions.should == positions.sort > end > response.should have_tag(''div.even>div'') do |match| > even = match[0] > positions = [] > with_tag(''div.label'', ''Login name:'') { |match| >positions << match[0].position } > with_tag(''div.info'', ''example login name 2'') { |match| >positions << match[0].position } > with_tag(''div.label'', ''Display name:'') { |match| >positions << match[0].position } > with_tag(''div.info'', ''example display name 2'') { |match| >positions << match[0].position } > with_tag(''div.label'', ''Email address:'') { |match| >positions << match[0].position } > with_tag(''div.info'', ''example email address 2'') { |match| >positions << match[0].position } > positions.should == positions.sort > end > odd.position.should < even.position > end >end > >Compare this to the version without the book-keeping: > >describe ''/users/index with 2 users'' do > before do > users = (1..2).inject([]) do |list, index| > user = mock("user #{index}") > user.should_receive(:login_name).and_return("example login >name #{index}") > user.should_receive(:display_name).and_return("example display >name #{index}") > user.should_receive(:email_address).and_return("example email >address #{index}") > list << user > end > assigns[:users] = users > render ''users/index'' > end > > it ''should display the login names, displays names and email >address, in alternating odd and even rows'' do > response.should have_tag(''div.odd>div'') do > with_tag(''div.label'', ''Login name:'') > with_tag(''div.info'', ''example login name 1'') > with_tag(''div.label'', ''Display name:'') > with_tag(''div.info'', ''example display name 1'') > with_tag(''div.label'', ''Email address:'') > with_tag(''div.info'', ''example email address 1'') > end > response.should have_tag(''div.even>div'') do > with_tag(''div.label'', ''Login name:'') > with_tag(''div.info'', ''example login name 2'') > with_tag(''div.label'', ''Display name:'') > with_tag(''div.info'', ''example display name 2'') > with_tag(''div.label'', ''Email address:'') > with_tag(''div.info'', ''example email address 2'') > end > end >end > >So, yes, the book-keeping-free version is much easier to look at, but >it''s also far too easy for the spec to pass with faulty input (jumble >the divs around in any order you want and it will still pass). So >improving have_tag, with_tag, or the underlying assert_select seems >to be a very worthwhile project; I''ve got a very basic prototype >implementation in place based on this small patch to actionpack/lib/ >action_controller/assertions/selector_assertions.rb: > >=== vendor/rails/actionpack/lib/action_controller/assertions/ >selector_assertions.rb >=================================================================>--- vendor/rails/actionpack/lib/action_controller/assertions/ >selector_assertions.rb (revision 7191) >+++ vendor/rails/actionpack/lib/action_controller/assertions/ >selector_assertions.rb (local) >@@ -286,6 +286,13 @@ > "Expected at most #{equals[:maximum]} elements, found # >{matches.size}." > end > >+ if !matches.empty? >+ if @previous_match and matches[0].position < >@previous_match.position >+ raise "selector order mismatch (''#{matches[0].to_s}'' at >position #{matches[0].position} appears before ''# >{@previous_match.to_s}'' at position #{@previous_match.position})" >+ end >+ @previous_match = matches[0] >+ end >+ > # If a block is given call that block. Set @selected to allow > # nested assert_select, which can be nested several levels >deep. > if block_given? && !matches.empty? > >Experimentation shows that the dynamic class created by RSpec for >each "it" block receives the assert_select messages and hangs around >for the duration of the block. So that means instance variables can >be used to store positional information and an exception can be >thrown if things don''t happen in the expected order. > >This works, at least for the sample spec I''ve posted above. In the >event of the ordering requirement failing the exception will include >diagnostic information that looks like this: > >selector order mismatch (''<div class="label">Display name:</div>'' at >position 109 appears before ''<div class="info">example login name 1</ >div>'' at position 150) > >Limitations, and doubts: > >- I don''t know what type of exception to throw, so for now I''m just >throwing a String (which becomes a RuntimeError) > >- no way to make it optional at this stage > >- this patch (or anything like it) is unlikely to get accepted in >Rails because it will probably break lots of existing specs/tests >which are written without caring about selector ordering > >Any further ideas? > >Cheers, >Wincent > >_______________________________________________ >rspec-users mailing list >rspec-users at rubyforge.org >http://rubyforge.org/mailman/listinfo/rspec-users
Wincent Colaiuta
2007-May-24 14:56 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
El 24/5/2007, a las 16:24, Matt Deiters escribi?:> A couple of questions/comments. Are you doing some sorting logic in > the view? If so I can see why you would want to assert order, but > perhaps it would be better to move that type of logic out of view > and into your controller (or perhaps a presenter or helper). Then > you would test the order of your collection in one of those (helper/ > controller) types of specs. Then your view would just iterate of > the collection and if your view is just iterating over the > collection, then when your testing order you would really be > testing does ''ruby iterate right'', which again is something we > don''t want to test in our views (or need test at all).No, the view has no sorting logic: <% for user in @users %> <div id="userlist"> <div class="<%= cycle(''odd'', ''even'') %>"> <div class="label">Login name:</div> <div class="info"><%=h user.login_name %></div> <div class="label">Display name:</div> <div class="info"><%=h user.display_name %></div> <div class="label">Email address:</div> <div class="info"><%=h user.email_address %></div> </div> </div> <% end %> But I do want to be sure of some things, and these stemmed out of behaviour-driving the development of the view. I basically imagined what I wanted the view to look like in my mind and started coming up with specifications: - users should be listed in rows - rows should have alternate classes (odd, even, odd, even) so they can be visually styled - there should be three fields for each user - the fields should appear in order: login name, display name, email address - each field should be preceded by the correct, corresponding label - users should appear in the view in the order that they were passed to it - etc So when I wrote the view based on the specs. I was dismayed to find that if I ignored the question of ordering then I could radically change the view and the specs would still pass, even though I the view no longer resembled what I wanted it to look like in my mind... Basically, I want to be able to assert that "rows should be odd, even" and only "odd, even" should pass, not "even, odd". Likewise, I want to be able to assert "header, content, footer" and not accept results like "footer, header, content" etc. In the case where order doesn''t matter at all and you only want to test for the presence of something on the page, you can easily do that with a single "have_tag" inside an example "it" block of its own. Cheers, Wincent
David Chelimsky
2007-May-29 02:00 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
On 5/24/07, Wincent Colaiuta <win at wincent.com> wrote:> El 24/5/2007, a las 16:24, Matt Deiters escribi?: > > > A couple of questions/comments. Are you doing some sorting logic in > > the view? If so I can see why you would want to assert order, but > > perhaps it would be better to move that type of logic out of view > > and into your controller (or perhaps a presenter or helper). Then > > you would test the order of your collection in one of those (helper/ > > controller) types of specs. Then your view would just iterate of > > the collection and if your view is just iterating over the > > collection, then when your testing order you would really be > > testing does ''ruby iterate right'', which again is something we > > don''t want to test in our views (or need test at all). > > No, the view has no sorting logic: > > <% for user in @users %> > <div id="userlist"> > <div class="<%= cycle(''odd'', ''even'') %>"> > <div class="label">Login name:</div> > <div class="info"><%=h user.login_name %></div> > <div class="label">Display name:</div> > <div class="info"><%=h user.display_name %></div> > <div class="label">Email address:</div> > <div class="info"><%=h user.email_address %></div> > </div> > </div> > <% end %> > > But I do want to be sure of some things, and these stemmed out of > behaviour-driving the development of the view. I basically imagined > what I wanted the view to look like in my mind and started coming up > with specifications: > > - users should be listed in rows > - rows should have alternate classes (odd, even, odd, even) so they > can be visually styled > - there should be three fields for each user > - the fields should appear in order: login name, display name, email > address > - each field should be preceded by the correct, corresponding label > - users should appear in the view in the order that they were passed > to it > - etc > > So when I wrote the view based on the specs. I was dismayed to find > that if I ignored the question of ordering then I could radically > change the view and the specs would still pass, even though I the > view no longer resembled what I wanted it to look like in my mind... > Basically, I want to be able to assert that "rows should be odd, > even" and only "odd, even" should pass, not "even, odd". Likewise, I > want to be able to assert "header, content, footer" and not accept > results like "footer, header, content" etc. > > In the case where order doesn''t matter at all and you only want to > test for the presence of something on the page, you can easily do > that with a single "have_tag" inside an example "it" block of its own.Actually - looking at assert_select (which have_tag and with_tag wrap), you should be able to get what you''re looking for using the nth-child selectors. Check it out: http://labnotes.org/svn/public/ruby/rails_plugins/assert_select/cheat/assert_select.html Let us know if it works.> > Cheers, > Wincent > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Wincent Colaiuta
2007-May-29 09:36 UTC
[rspec-users] Ordering in view specs using have_tag and with_tag
El 29/5/2007, a las 4:00, David Chelimsky escribi?:> Actually - looking at assert_select (which have_tag and with_tag > wrap), you should be able to get what you''re looking for using the > nth-child selectors. Check it out: > > http://labnotes.org/svn/public/ruby/rails_plugins/assert_select/ > cheat/assert_select.htmlGreat cheat sheet, that one! Thanks for sharing the link. There''s also a PDF if anyone wants to print it out: http://labnotes.org/svn/public/ruby/rails_plugins/assert_select/cheat/ assert_select.pdf Yes, I think that would definitely work. If we add that to the list of possible techniques we now have three levels of specificity; working from least to most specific we have: 1. No ordering requirements, when you only care about the presence of tags on the page. 2. Strict ordering requirement, as implemented by the assert_select patch that I posted, where you expect tags to appear in the order that you assert them in your specs. 3. Ultra-strict positioning, using the nth-child selectors as you suggest, where you not only care about the order of the tags but specify their numeric position within the list. Obviously as you move through the list from less to more specific your specs become more tightly bound to the structural details of the view, it becomes harder to change the view without breaking the specs, which in turn means you''ll tend to pick up mistakes in the view more quickly, but you''ll also have a lot more duplication between view and spec. So I guess it''s a matter of choosing the right tool for each case. Cheers, Wincent