describe "Fortitude tag rendering", :type => :system do def r(&block) render(widget_class_with_content(&block)) end def should_render_to(value, &block) expect(r(&block)).to eq(value) end it "should allow passing numbers to a tag" do should_render_to("
123.45
") { p(123.45) } end it "should allow rendering nil to a tag" do should_render_to("") { p(nil) } end it "should allow rendering nil via text" do should_render_to("") { text(nil) } end it "should allow rendering nil via rawtext" do should_render_to("") { rawtext(nil) } end it "should render an attribute mapped to nil as missing" do should_render_to("") { p(:class => nil) } should_render_to("") { p(:foo => { :bar => nil }) } end it "should render an attribute mapped to the empty string as the empty string" do should_render_to("") { p(:class => '') } should_render_to("") { p(:foo => { :bar => '' }) } end it "should render an attribute mapped to false as missing" do should_render_to("") { p(:class => false) } should_render_to("") { p(:foo => { :bar => false }) } end it "should render an attribute mapped to true as just a bare attribute" do should_render_to("") { p(:class => true) } should_render_to("") { p(:foo => { :bar => true }) } end it "should render an attribute mapped to the string 'true' as that string" do should_render_to("") { p(:class => 'true') } should_render_to("") { p(:foo => { :bar => 'true' }) } end it "should render a void tag correctly" do should_render_to("hello, world
") { p "hello, world" } end it "should render a tag with numeric content correctly" do should_render_to("12345
") { p 12345 } end it "should render a tag using a specific tag_* method" do should_render_to("foo
") { tag_p "foo" } end it "should let you override a tag and use #super" do wc = widget_class do def p(data, options = { }) text "before_p" super(data, { :bar => 'baz' }.merge(options)) text("after_p") end def content text "yo" p "hello" text "bye" end end expect(render(wc)).to eq("yobefore_phello
after_pbye") end it "should let you override a tag and use #super, even if it's defined directly on that widget class" do wc = widget_class do tag :mytag def mytag(data, options = { }) text "before_mytag" super(data, { :bar => 'baz' }.merge(options)) text("after_mytag") end def content text "yo" mytag "hello" text "bye" end end expect(render(wc)).to eq("yobefore_mytagthis is <>&" foo!
") { p foo } end it "should escape content directly passed to a tag" do should_render_to("<hello> "world&
") { p "hello, world
") { p { text "hello, world" } } end it "should render an empty tag given an empty block" do should_render_to("") { p { } } end it "should render with both attributes and a block" do result = r { p(:class => 'foo', :bar => 'baz') { text "hello, world" } } expect(result).to match(%r{^hello, world
$}) expect(result).to match(%r{ class=\"foo\"}) expect(result).to match(%r{ bar=\"baz\"}) end it "should render with both attributes and direct content" do result = r { p("hello, world", :class => 'foo', :bar => 'baz') } expect(result).to match(%r{^hello, world
$}) expect(result).to match(%r{ class=\"foo\"}) expect(result).to match(%r{ bar=\"baz\"}) end it "should render with both direct content and a block" do should_render_to("hello, worldbienvenue, le monde
") { p("hello, world") { text "bienvenue, le monde" } } end it "should render with both attributes and a block" do result = r { p(:class => :foo, :bar => :baz) { text "hello, world" } } expect(result).to match(%r{^hello, world
$}) expect(result).to match(%r{ class=\"foo\"}) expect(result).to match(%r{ bar=\"baz\"}) end it "should render with attributes, direct content, and a block" do result = r { p("hello, world", :class => :foo, :bar => :baz) { text "bienvenue, le monde" } } expect(result).to match(%r{^hello, worldbienvenue, le monde
$}) expect(result).to match(%r{ class=\"foo\"}) expect(result).to match(%r{ bar=\"baz\"}) end it "should render attribute values that are hashes as a sequence of prefixed attributes" do result = r { p :data => { :foo => 'bar', :bar => 'baz' } } expect(result).to match(%r{^$}) expect(result).to match(%r{ data-foo=\"bar\"}) expect(result).to match(%r{ data-bar=\"baz\"}) end it "should render an arbitrary object as an attribute key, escaping it" do foo = arbitrary_object_with_to_s("and&<>\"this") should_render_to("") { p foo => "bar" } end it "should render an arbitrary object as an attribute value, escaping it" do foo = arbitrary_object_with_to_s("and&<>\"this") should_render_to("") { p :foo => foo } end it "should render an arbitrary object as an attribute key nested in a hash, escaping it" do foo = arbitrary_object_with_to_s("and&<>\"this") should_render_to("") { p :data => { foo => "bar" } } end it "should render an arbitrary object as an attribute value nested in a hash, escaping it" do foo = arbitrary_object_with_to_s("and&<>\"this") should_render_to("") { p :data => { foo => "bar" } } end it "should allow an arbitrary object as an attribute key, mapping to a hash" do foo = arbitrary_object_with_to_s("and&<>\"this") result = r { p foo => { :foo => 'bar', :bar => 'baz' } } expect(result).to match(%r{^$}) expect(result).to match(%r{ and&<>"this-foo=\"bar\"}) expect(result).to match(%r{ and&<>"this-bar=\"baz\"}) end it "should allow multi-level hash nesting" do result = r { p :foo => { :bar => 'bar', :baz => { :a => 'xxx', 'b' => :yyy } } } expect(result).to match(%r{^}) expect(result).to match(%r{ foo-bar=\"bar\"}) expect(result).to match(%r{ foo-baz-a=\"xxx\"}) expect(result).to match(%r{ foo-baz-b=\"yyy\"}) end it "should allow arrays as attribute values, separating elements with spaces" do should_render_to("") { p :foo => [ 'bar', 'baz', 'quux' ]} end it "should allow arrays as attribute values, calling #to_s on values in them" do quux = arbitrary_object_with_to_s("quux") should_render_to("") { p :foo => [ 'bar', :baz, quux ]} end end