I'd opened Fortitude Issue #28 over some problems I'd been having with unit testing of Widgets that conditionally yielded to their blocks. I've included the two directly relevant code files as they existed when the issue was opened.
A slightly simplified version of my attempted spec (using MiniTest::Spec) is included in simple_container_v1_test.rb
, along with the test_helper.rb
support file. This is what led to the filing of the issue, when running that test produced the output
# Running tests with run options --seed 42296:
E
Error:
Views::Welcome::Index::SimpleContainer::produces output from the #to_html method that#test_0001_is wrapped in a :div element with the .container CSS style:
Fortitude::Errors::NoBlockToYieldTo: You're trying to call 'yield' (or 'yield_from_widget', or the Erector-compatibility method 'call_block')
from the widget #<Views::Welcome::Index::SimpleContainer:0x007fceb2d12968>; however, there is nothing to yield to. Fortitude
looks for something to yield to in this order:
1. A block passed to a yield at render time directly (usually via the 'widget' call);
2. A block passed to the constructor of the widget;
3. The layout the widget is being rendered in.
None of these exist here, and so calling 'yield', 'yield_from_widget', or 'call_block' is an
undefined operation.
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/rendering_context.rb:192:in `yield_from_widget'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:120:in `_fortitude_yield_from_widget'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:126:in `yield_from_widget'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:31:in `block in render_to'
/Users/jeffdickey/src/rails/meldd/meldd1/app/views/welcome/index/simple_container.rb:7:in `block in content'
(eval):36:in `block in tag_div'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/rendering_context.rb:114:in `emitting_tag!'
(eval):6:in `tag_div'
/Users/jeffdickey/src/rails/meldd/meldd1/app/views/welcome/index/simple_container.rb:7:in `content'
(eval):3:in `run_content'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:35:in `block in render_to'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/rendering_context.rb:79:in `record_widget'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:33:in `render_to'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:64:in `widget'
test/views/welcome/index/simple_container_test.rb:12:in `content'
(eval):3:in `run_content'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:35:in `block in render_to'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/rendering_context.rb:79:in `record_widget'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:33:in `render_to'
/Users/jeffdickey/src/rails/meldd/meldd1/vendor/ruby/2.2.0/gems/fortitude-0.9.4/lib/fortitude/widget/rendering.rb:45:in `to_html'
test/views/welcome/index/simple_container_test.rb:8:in `block (2 levels) in <main>'
Finished tests in 0.007187s, 139.1338 tests/s, 0.0000 assertions/s.
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
UPDATE 19 July 14:23 (GMT+8): I was able to successfully unit test the widget using the spec code in simple_container_v2_test.rb
below. What was required was to
- Create a subclass of the class under test, whose
#content
called the widget with a block; - Instantiate that subclass, essentially as the new SUT;
- Examine the output of the subclass'
#to_html
method.
It seems that MiniTest, when evaluating the original widget class, ignores the if block_given?
conditional on the yield
, and thus chokes when no block is specified.