1 require File.dirname(__FILE__) + '/../spec_helper'
3 describe "Standard Tags" do
4 scenario :users_and_pages, :file_not_found, :snippets
6 specify '<r:page> should allow access to the current page' do
8 page.should render('<r:page:title />').as('Home')
9 page.should render(%{<r:find url="/radius"><r:title /> | <r:page:title /></r:find>}).as('Radius | Home')
12 specify '<r:breadcrumb>, <r:slug>, <r:title>, and <r:url>' do
14 [:breadcrumb, :slug, :title, :url].each do |attr|
15 value = page.send(attr)
16 page.should render("<r:#{attr} />").as(value.to_s)
20 specify '<r:parent>' do
22 page.should render('<r:parent><r:title /></r:parent>').as(pages(:home).title)
23 page.should render('<r:parent><r:children:each by="title"><r:title /></r:children:each></r:parent>').as(page_eachable_children(pages(:home)).collect(&:title).join(""))
24 page.should render('<r:children:each><r:parent:title /></r:children:each>').as(@page.title * page.children.count)
27 specify '<r:if_parent>' do
28 page.should render('<r:if_parent>true</r:if_parent>').as('true')
29 page(:home).should render('<r:if_parent>true</r:if_parent>').as('')
32 specify '<r:unless_parent>' do
33 page.should render('<r:unless_parent>true</r:unless_parent>').as('')
34 page(:home).should render('<r:unless_parent>true</r:unless_parent>').as('true')
37 specify '<r:if_children>' do
38 page(:home).should render('<r:if_children>true</r:if_children>').as('true')
39 page(:childless).should render('<r:if_children>true</r:if_children>').as('')
42 specify '<r:unless_children>' do
43 page(:home).should render('<r:unless_children>true</r:unless_children>').as('')
44 page(:childless).should render('<r:unless_children>true</r:unless_children>').as('true')
47 specify '<r:children:each>' do
49 page.should render('<r:children:each><r:title /> </r:children:each>').as('Child Child 2 Child 3 ')
50 page.should render('<r:children:each><r:page><r:slug />/<r:child:slug /> </r:page></r:children:each>').as('parent/child parent/child-2 parent/child-3 ')
52 specify '<r:children:each> order attributes' do
53 page.should render(page_children_each_tags).as('a b c d e f g h i j ')
54 page.should render(page_children_each_tags(%{limit="5"})).as('a b c d e ')
55 page.should render(page_children_each_tags(%{offset="3" limit="5"})).as('d e f g h ')
56 page.should render(page_children_each_tags(%{order="desc"})).as('j i h g f e d c b a ')
57 page.should render(page_children_each_tags(%{by="breadcrumb"})).as('f e d c b a j i h g ')
58 page.should render(page_children_each_tags(%{by="breadcrumb" order="desc"})).as('g h i j a b c d e f ')
60 specify '<r:children:each> with "status" attribute' do
61 page.should render(page_children_each_tags(%{status="all"})).as("a b c d e f g h i j draft ")
62 page.should render(page_children_each_tags(%{status="draft"})).as('draft ')
63 page.should render(page_children_each_tags(%{status="published"})).as('a b c d e f g h i j ')
64 page.should render(page_children_each_tags(%{status="askdf"})).with_error("`status' attribute of `each' tag must be set to a valid status")
66 specify '<r:children:each> should not list virtual pages' do
67 page.should render('<r:children:each><r:slug /> </r:children:each>').as('a b c d e f g h i j ')
68 page.should render('<r:children:each status="all"><r:slug /> </r:children:each>').as('a b c d e f g h i j draft ')
70 specify '<r:children:each> should error with invalid "limit" attribute' do
71 message = "`limit' attribute of `each' tag must be a positive number between 1 and 4 digits"
72 page.should render(page_children_each_tags(%{limit="a"})).with_error(message)
73 page.should render(page_children_each_tags(%{limit="-10"})).with_error(message)
74 page.should render(page_children_each_tags(%{limit="50000"})).with_error(message)
76 specify '<r:children:each> should error with invalid "offset" attribute' do
77 message = "`offset' attribute of `each' tag must be a positive number between 1 and 4 digits"
78 page.should render(%{offset="a"}).with_error(message)
79 page.should render(%{offset="-10"}).with_error(message)
80 page.should render(%{offset="50000"}).with_error(message)
82 specify '<r:children:each> should error with invalid "by" attribute' do
83 message = "`by' attribute of `each' tag must be set to a valid field name"
84 page.should render(page_children_each_tags(%{by="non-existant-field"})).with_error(message)
86 specify '<r:children:each> should error with invalid "order" attribute' do
87 message = %{`order' attribute of `each' tag must be set to either "asc" or "desc"}
88 page.should render(page_children_each_tags(%{order="asdf"})).with_error(message)
91 specify '<r:children:each:header>' do
92 tags = '<r:children:each><r:header>[<r:date format="%b/%y" />] </r:header><r:slug /> </r:children:each>'
93 expected = "[Dec/00] article [Feb/01] article-2 article-3 [Mar/01] article-4 "
94 page(:news).should render(tags).as(expected)
96 specify '<r:children:each:header> with "name" attribute' do
97 tags = %{<r:children:each><r:header name="year">[<r:date format='%Y' />] </r:header><r:header name="month">(<r:date format="%b" />) </r:header><r:slug /> </r:children:each>}
98 expected = "[2000] (Dec) article [2001] (Feb) article-2 article-3 (Mar) article-4 "
99 page(:news).should render(tags).as(expected)
101 specify '<r:children:each:header> with "restart" attribute set to one name' do
102 tags = %{<r:children:each><r:header name="year" restart="month">[<r:date format='%Y' />] </r:header><r:header name="month">(<r:date format="%b" />) </r:header><r:slug /> </r:children:each>}
103 expected = "[2000] (Dec) article [2001] (Feb) article-2 article-3 (Mar) article-4 "
104 page(:news).should render(tags).as(expected)
106 specify '<r:children:each:header> with "restart" attribute set to two names' do
107 tags = %{<r:children:each><r:header name="year" restart="month;day">[<r:date format='%Y' />] </r:header><r:header name="month" restart="day">(<r:date format="%b" />) </r:header><r:header name="day"><<r:date format='%d' />> </r:header><r:slug /> </r:children:each>}
108 expected = "[2000] (Dec) <01> article [2001] (Feb) <09> article-2 <24> article-3 (Mar) <06> article-4 "
109 page(:news).should render(tags).as(expected)
112 specify '<r:children:count>' do
113 page(:parent).should render('<r:children:count />').as('3')
116 specify '<r:children:first>' do
117 page(:parent).should render('<r:children:first:title />').as('Child')
119 specify '<r:children:first> with attributes' do
120 page.should render(page_children_first_tags).as('a')
121 page.should render(page_children_first_tags(%{limit="5"})).as('a')
122 page.should render(page_children_first_tags(%{offset="3" limit="5"})).as('d')
123 page.should render(page_children_first_tags(%{order="desc"})).as('j')
124 page.should render(page_children_first_tags(%{by="breadcrumb"})).as('f')
125 page.should render(page_children_first_tags(%{by="breadcrumb" order="desc"})).as('g')
127 specify '<r:children:first> when no children exist' do
128 page(:first).should render('<r:children:first:title />').as('')
131 specify '<r:children:last>' do
132 page(:parent).should render('<r:children:last:title />').as('Child 3')
134 specify '<r:children:last> with attributes' do
135 page.should render(page_children_last_tags).as('j')
136 page.should render(page_children_last_tags(%{limit="5"})).as('e')
137 page.should render(page_children_last_tags(%{offset="3" limit="5"})).as('h')
138 page.should render(page_children_last_tags(%{order="desc"})).as('a')
139 page.should render(page_children_last_tags(%{by="breadcrumb"})).as('g')
140 page.should render(page_children_last_tags(%{by="breadcrumb" order="desc"})).as('f')
142 specify '<r:children:last> when no children exist' do
143 page(:first).should render('<r:children:last:title />').as('')
146 specify '<r:content>' do
147 page.should render('<r:content />').as('Assorted body.')
149 specify '<r:content> with "part" attribute' do
150 page(:home).should render('<r:content part="extended" />').as("Just a test.")
152 specify '<r:content> with inherit attribute' do
153 page.should render('<r:content part="sidebar" />').as('')
154 page.should render('<r:content part="sidebar" inherit="false" />').as('')
155 page.should render('<r:content part="sidebar" inherit="true" />').as('Assorted sidebar.')
156 page.should render('<r:content part="sidebar" inherit="weird value" />').with_error(%{`inherit' attribute of `content' tag must be set to either "true" or "false"})
157 page.should render('<r:content part="part_that_doesnt_exist" inherit="true" />').as('')
159 specify '<r:content> with inherit and contextual attributes' do
161 page.should render('<r:content part="sidebar" inherit="true" contextual="true" />').as('Parent sidebar.')
162 page.should render('<r:content part="sidebar" inherit="true" contextual="false" />').as('Home sidebar.')
163 page(:child).should render('<r:content part="sidebar" inherit="true" contextual="true" />').as('Child sidebar.')
164 page(:grandchild).should render('<r:content part="sidebar" inherit="true" contextual="true" />').as('Grandchild sidebar.')
166 specify '<r:content> with global page propagation' do
168 page.should render('<r:content part="titles" inherit="true" contextual="true"/>').as('First First')
169 page.should render('<r:content part="titles" inherit="true" contextual="false"/>').as('Home First')
171 specify '<r:content /> for children' do
172 expected = "Child body. Child 2 body. Child 3 body. "
173 page(:parent).should render('<r:children:each><r:content /> </r:children:each>').as(expected)
176 specify '<r:if_content> without "part" attribute' do
177 page.should render('<r:if_content>true</r:if_content>').as('true')
179 specify '<r:if_content> with "part" attribute' do
180 page.should render('<r:if_content part="body">true</r:if_content>').as('true')
182 specify '<r:if_content> with nonexistant "part" attribute' do
183 page.should render('<r:if_content part="asdf">true</r:if_content>').as('')
186 specify '<r:unless_content> without "part" attribute' do
187 page.should render('<r:unless_content>false</r:unless_content>').as('')
189 specify '<r:unless_content> with "part" attribute' do
190 page.should render('<r:unless_content part="body">false</r:unless_content>').as('')
192 specify '<r:unless_content> with nonexistant "part" attribute' do
193 page.should render('<r:unless_content part="asdf">false</r:unless_content>').as('false')
196 specify '<r:author>' do
197 page.should render('<r:author />').as('Admin')
199 specify '<r:author> nil' do
200 page(:no_user).should render('<r:author />').as('')
203 specify '<r:date>' do
205 page.should render('<r:date />').as('Wednesday, January 11, 2006')
207 specify '<r:date> with "format" attribute' do
209 page.should render('<r:date format="%d %b %Y" />').as('11 Jan 2006')
211 specify '<r:date> with "for" attribute' do
213 page.should render('<r:date for="now" />').as(Time.now.strftime("%A, %B %d, %Y"))
214 page.should render('<r:date for="created_at" />').as('Tuesday, January 10, 2006')
215 page.should render('<r:date for="updated_at" />').as('Thursday, January 12, 2006')
216 page.should render('<r:date for="published_at" />').as('Wednesday, January 11, 2006')
217 page.should render('<r:date for="blah" />').with_error("Invalid value for 'for' attribute.")
219 specify '<r:date> should use local timezone' do
221 Radiant::Config["local.timezone"] = "Tokyo"
223 expected = TimeZone["Tokyo"].adjust(page.published_at).strftime(format)
224 page.should render(%Q(<r:date format="#{format}" />) ).as(expected)
227 specify '<r:link>' do
228 page.should render('<r:link />').as('<a href="/assorted/">Assorted</a>')
230 specify '<r:link> in block form' do
231 page.should render('<r:link>Test</r:link>').as('<a href="/assorted/">Test</a>')
233 specify '<r:link> with HTML attributes' do
234 expected = '<a href="/assorted/" class="test" id="assorted">Assorted</a>'
235 page.should render('<r:link class="test" id="assorted" />').as(expected)
237 specify '<r:link> with "anchor" attribute' do
238 page.should render('<r:link anchor="test">Test</r:link>').as('<a href="/assorted/#test">Test</a>')
240 specify '<r:link> should work for children' do
241 expected = %{<a href="/parent/child/">Child</a> <a href="/parent/child-2/">Child 2</a> <a href="/parent/child-3/">Child 3</a> }
242 page(:parent).should render('<r:children:each><r:link /> </r:children:each>' ).as(expected)
245 specify '<r:snippet>' do
246 page.should render('<r:snippet name="first" />').as('test')
248 specify '<r:snippet> not found' do
249 page.should render('<r:snippet name="non-existant" />').with_error('snippet not found')
251 specify '<r:snippet> without name' do
252 page.should render('<r:snippet />').with_error("`snippet' tag must contain `name' attribute")
254 specify '<r:snippet> with markdown' do
255 page.should render('<r:page><r:snippet name="markdown" /></r:page>').as('<p><strong>markdown</strong></p>')
257 specify '<r:snippet> with global page propagation' do
258 page(:parent).should render('<r:snippet name="global_page_cascade" />').as("#{@page.title} " * @page.children.count)
260 specify '<r:snippet> with recursion global page propagation' do
261 page(:child).should render('<r:snippet name="recursive" />').as("Great GrandchildGrandchildChild")
264 specify '<r:random>' do
265 page.should render("<r:random> <r:option>1</r:option> <r:option>2</r:option> <r:option>3</r:option> </r:random>").matching(/^(1|2|3)$/)
268 specify '<r:comment>' do
269 page.should render('just a <r:comment>small </r:comment>test').as('just a test')
272 specify '<r:navigation> simple case' do
273 tags = %{<r:navigation urls="Home: / | Assorted: /assorted/ | Parent: /parent/">
274 <r:normal><r:title /></r:normal>
276 expected = %{Home Assorted Parent}
277 page.should render(tags).as(expected)
279 specify '<r:navigation> more complex' do
280 tags = %{<r:navigation urls="Home: / | Assorted: /assorted/ | Parent: /parent/ | Radius: /radius/">
281 <r:normal><r:title /></r:normal>
282 <r:selected><strong><r:title/></strong></r:selected>
284 expected = %{<strong>Home</strong> Assorted <strong>Parent</strong> Radius}
285 page(:parent).should render(tags).as(expected)
287 specify '<r:navigation> very complex' do
288 tags = %{<r:navigation urls="Home: Boy: / | Assorted: /assorted/ | Parent: /parent/">
289 <r:normal><a href="<r:url />"><r:title /></a></r:normal>
290 <r:here><strong><r:title /></strong></r:here>
291 <r:selected><strong><a href="<r:url />"><r:title /></a></strong></r:selected>
292 <r:between> | </r:between>
294 expected = %{<strong><a href="/">Home: Boy</a></strong> | <strong>Assorted</strong> | <a href="/parent/">Parent</a>}
295 page.should render(tags).as(expected)
297 specify '<r:navigation> without urls' do
298 page.should render(%{<r:navigation><r:normal /></r:navigation>}).as('')
300 specify '<r:navigation> without normal tag' do
301 page.should render(%{<r:navigation urls="something:here"></r:navigation>}).with_error( "`navigation' tag must include a `normal' tag")
303 specify '<r:navigation> with urls without slashes' do
304 tags = %{<r:navigation urls="Home: / | Assorted: /assorted/ | Parent: /parent/ | Radius: /radius/">
305 <r:normal><r:title /></r:normal>
306 <r:here><strong><r:title /></strong></r:here>
308 expected = %{Home <strong>Assorted</strong> Parent Radius}
309 page.should render(tags).as(expected)
312 specify '<r:find>' do
313 page.should render(%{<r:find url="/parent/child/"><r:title /></r:find>}).as('Child')
315 specify '<r:find> without url' do
316 page.should render(%{<r:find />}).with_error("`find' tag must contain `url' attribute")
318 specify '<r:find> with nonexistant url' do
319 page.should render(%{<r:find url="/asdfsdf/"><r:title /></r:find>}).as('')
321 specify '<r:find> with nonexistant url and file not found' do
322 page.should render(%{<r:find url="/gallery/asdfsdf/"><r:title /></r:find>}).as('')
324 specify '<r:find> with children' do
325 page.should render(%{<r:find url="/parent/"><r:children:each><r:slug /> </r:children:each></r:find>}).as('child child-2 child-3 ')
328 specify '<r:escape_html>' do
329 page.should render('<r:escape_html><strong>a bold move</strong></r:escape_html>').as('<strong>a bold move</strong>')
332 specify '<r:rfc1123_date>' do
333 page(:dated).should render('<r:rfc1123_date />').as('Wed, 11 Jan 2006 00:00:00 GMT')
336 specify '<r:breadcrumbs>' do
337 expected = %{<a href="/">Home</a> > <a href="/parent/">Parent</a> > <a href="/parent/child/">Child</a> > <a href="/parent/child/grandchild/">Grandchild</a> > Great Grandchild}
338 page(:great_grandchild).should render('<r:breadcrumbs />').as(expected)
340 specify '<r:breadcrumbs> with separator attribute' do
341 expected = %{<a href="/">Home</a> :: Parent}
342 page(:parent).should render('<r:breadcrumbs separator=" :: " />').as(expected)
345 specify '<r:if_url> with "matches" attribute' do
346 page.should render('<r:if_url matches="a.sorted/$">true</r:if_url>').as('true')
348 specify '<r:if_url> with "matches" attribute that does not match' do
349 page.should render('<r:if_url matches="fancypants">true</r:if_url>').as('')
351 specify '<r:if_url> with "matches" attribute set to a malformatted regexp' do
352 page.should render('<r:if_url matches="as(sorted/$">true</r:if_url>').with_error("Malformed regular expression in `matches' argument of `if_url' tag: unmatched (: /as(sorted\\/$/")
354 specify '<r:if_url> without "ignore_case" attribute' do
355 page.should render('<r:if_url matches="asSorted/$">true</r:if_url>').as('true')
357 specify '<r:if_url> with "ignore_case" attribute set to "true"' do
358 page.should render('<r:if_url matches="asSorted/$" ignore_case="true">true</r:if_url>').as('true')
360 specify '<r:if_url> with "ignore_case" attribute set to "false"' do
361 page.should render('<r:if_url matches="asSorted/$" ignore_case="false">true</r:if_url>').as('')
363 specify '<r:if_url> with no attributes' do
364 page.should render('<r:if_url>test</r:if_url>').with_error("`if_url' tag must contain a `matches' attribute.")
367 specify '<r:unless_url> with "matches" attribute' do
368 page.should render('<r:unless_url matches="a.sorted/$">true</r:unless_url>').as('')
370 specify '<r:unless_url> with "matches" attribute that does not match' do
371 page.should render('<r:unless_url matches="fancypants">true</r:unless_url>').as('true')
373 specify '<r:unless_url> with "matches" attribute set to a malformatted regexp' do
374 page.should render('<r:unless_url matches="as(sorted/$">true</r:unless_url>').with_error("Malformed regular expression in `matches' argument of `unless_url' tag: unmatched (: /as(sorted\\/$/")
376 specify '<r:unless_url> without "ignore_case" attribute' do
377 page.should render('<r:unless_url matches="asSorted/$">true</r:unless_url>').as('')
379 specify '<r:unless_url> with "ignore_case" attribute set to "true"' do
380 page.should render('<r:unless_url matches="asSorted/$" ignore_case="true">true</r:unless_url>').as('')
382 specify '<r:unless_url> with "ignore_case" attribute set to "false"' do
383 page.should render('<r:unless_url matches="asSorted/$" ignore_case="false">true</r:unless_url>').as('true')
385 specify '<r:unless_url> with no attributes' do
386 page.should render('<r:unless_url>test</r:unless_url>').with_error("`unless_url' tag must contain a `matches' attribute.")
389 specify '<r:cycle>' do
390 page.should render('<r:cycle values="first, second" /> <r:cycle values="first, second" />').as('first second')
392 specify '<r:cycle> returns to beginning' do
393 page.should render('<r:cycle values="first, second" /> <r:cycle values="first, second" /> <r:cycle values="first, second" />').as('first second first')
395 specify '<r:cycle> default name' do
396 page.should render('<r:cycle values="first, second" /> <r:cycle values="first, second" name="cycle" />').as('first second')
398 specify '<r:cycle> keeps separate counters' do
399 page.should render('<r:cycle values="first, second" /> <r:cycle values="one, two" name="numbers" /> <r:cycle values="first, second" /> <r:cycle values="one, two" name="numbers" />').as('first one second two')
401 specify '<r:cycle> resets counter' do
402 page.should render('<r:cycle values="first, second" /> <r:cycle values="first, second" reset="true"/>').as('first first')
404 specify '<r:cycle> names empty' do
405 page.should render('<r:cycle />').with_error("`cycle' tag must contain a `values' attribute.")
408 specify '<r:if_dev>' do
409 page.should render('-<r:if_dev>dev</r:if_dev>-').as('-dev-').on('dev.site.com')
410 page.should render('-<r:if_dev>dev</r:if_dev>-').as('--')
412 specify '<r:if_dev> on included page' do
413 page.should render('-<r:find url="/devtags/"><r:content part="if_dev" /></r:find>-').as('-dev-').on('dev.site.com')
414 page.should render('-<r:find url="/devtags/"><r:content part="if_dev" /></r:find>-').as('--')
417 specify '<r:unless_dev>' do
418 page.should render('-<r:unless_dev>not dev</r:unless_dev>-').as('--').on('dev.site.com')
419 page.should render('-<r:unless_dev>not dev</r:unless_dev>-').as('-not dev-')
421 specify '<r:unless_dev> on included page' do
422 page.should render('-<r:find url="/devtags/"><r:content part="unless_dev" /></r:find>-').as('--').on('dev.site.com')
423 page.should render('-<r:find url="/devtags/"><r:content part="unless_dev" /></r:find>-').as('-not dev-')
428 def page(symbol = nil)
430 @page ||= pages(:assorted)
432 @page = pages(symbol)
436 def page_children_each_tags(attr = nil)
437 attr = ' ' + attr unless attr.nil?
438 "<r:children:each#{attr}><r:slug /> </r:children:each>"
441 def page_children_first_tags(attr = nil)
442 attr = ' ' + attr unless attr.nil?
443 "<r:children:first#{attr}><r:slug /></r:children:first>"
446 def page_children_last_tags(attr = nil)
447 attr = ' ' + attr unless attr.nil?
448 "<r:children:last#{attr}><r:slug /></r:children:last>"
451 def page_eachable_children(page)
452 page.children.select(&:published?).reject(&:virtual)