View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.view.facelets.tag.ui.template;
20  
21  import java.io.StringWriter;
22  import javax.faces.application.ViewHandler;
23  
24  import javax.faces.component.UIViewRoot;
25  
26  import org.apache.myfaces.test.mock.MockResponseWriter;
27  import org.apache.myfaces.view.facelets.FaceletTestCase;
28  import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
29  import org.junit.Assert;
30  import org.junit.Test;
31  
32  public class CompositionTestCase extends FaceletTestCase {
33  
34      @Override
35      protected void setUpServletObjects() throws Exception
36      {
37          super.setUpServletObjects();
38          servletContext.addInitParameter(ViewHandler.FACELETS_SKIP_COMMENTS_PARAM_NAME, "true");
39      }
40  
41      /**
42       * Test if ui:composition is used on a page without a reference to a
43       * template, it should trim everything outside the template
44       * @throws Exception
45       */
46      @Test
47      public void testCompositionTrimEffect() throws Exception {
48          UIViewRoot root = facesContext.getViewRoot();
49          vdl.buildView(facesContext, root, "compositionTrim.xhtml");
50          
51          StringWriter sw = new StringWriter();
52          MockResponseWriter mrw = new MockResponseWriter(sw);
53          facesContext.setResponseWriter(mrw);
54          root.encodeAll(facesContext);
55          sw.flush();
56          
57          String response = sw.toString();
58          Assert.assertTrue(response.contains("THIS SHOULD BE RENDERED"));
59          Assert.assertFalse(response.contains("THIS SHOULD NOT BE RENDERED"));
60      }
61  
62      /**
63       * Test if ui:composition is used on a page with a reference to a
64       * template, it should trim everything, but take its content and insert it
65       * on a template ui:insert without name spot if available. It also test
66       * if no definition for a ui:insert with name is set, just render the content
67       * inside ui:insert 
68       * 
69       * @throws Exception
70       */
71      @Test
72      public void testComposition1() throws Exception {
73          UIViewRoot root = facesContext.getViewRoot();
74          vdl.buildView(facesContext, root, "composition1.xhtml");
75          
76          StringWriter sw = new StringWriter();
77          MockResponseWriter mrw = new MockResponseWriter(sw);
78          facesContext.setResponseWriter(mrw);
79          root.encodeAll(facesContext);
80          sw.flush();
81          
82          String response = sw.toString();
83          Assert.assertTrue(response.contains("fragmentNumber1"));
84          Assert.assertTrue(response.contains("compositionContent"));
85          Assert.assertFalse(response.contains("This fragment will not be inserted"));
86          Assert.assertFalse(response.contains("THIS SHOULD NOT BE RENDERED"));
87      }
88  
89      /**
90       * An empty ui:composition does not means the content of a ui:insert without
91       * name to be rendered
92       * 
93       * @throws Exception
94       */
95      @Test
96      public void testComposition2EmptyComposition() throws Exception {
97          UIViewRoot root = facesContext.getViewRoot();
98          vdl.buildView(facesContext, root, "composition2.xhtml");
99          
100         StringWriter sw = new StringWriter();
101         MockResponseWriter mrw = new MockResponseWriter(sw);
102         facesContext.setResponseWriter(mrw);
103         root.encodeAll(facesContext);
104         sw.flush();
105         
106         String response = sw.toString();
107         Assert.assertFalse(response.contains("This fragment will not be inserted"));
108         Assert.assertFalse(response.contains("THIS SHOULD NOT BE RENDERED"));
109     }
110     
111     /**
112      * An empty ui:composition does not means the content of a ui:insert without
113      * name to be rendered
114      * 
115      * @throws Exception
116      */
117     @Test
118     public void testComposition3EmptyComposition() throws Exception {
119         UIViewRoot root = facesContext.getViewRoot();
120         vdl.buildView(facesContext, root, "composition3.xhtml");
121         
122         StringWriter sw = new StringWriter();
123         MockResponseWriter mrw = new MockResponseWriter(sw);
124         facesContext.setResponseWriter(mrw);
125         root.encodeAll(facesContext);
126         sw.flush();
127         
128         String response = sw.toString();
129         Assert.assertFalse(response.contains("This fragment will not be inserted"));
130         Assert.assertFalse(response.contains("THIS SHOULD NOT BE RENDERED"));
131     }
132     
133     /**
134      * A ui:define takes precedence over a ui:insert
135      * 
136      * @throws Exception
137      */
138     @Test
139     public void testComposition4DefineOverInsert() throws Exception {
140         UIViewRoot root = facesContext.getViewRoot();
141         vdl.buildView(facesContext, root, "composition4.xhtml");
142         
143         StringWriter sw = new StringWriter();
144         MockResponseWriter mrw = new MockResponseWriter(sw);
145         facesContext.setResponseWriter(mrw);
146         root.encodeAll(facesContext);
147         sw.flush();
148         
149         String response = sw.toString();
150         Assert.assertTrue(response.contains("fragmentNumber1"));
151         Assert.assertFalse(response.contains("This fragment will not be inserted"));
152         Assert.assertFalse(response.contains("THIS SHOULD NOT BE RENDERED"));
153     }
154     
155     /**
156      * A ui:insert on nested composition takes the top TemplateClient.
157      * 
158      * In few words, ui:composition acts like a decorator pattern, so it allows
159      * override all definitions from other templates that uses ui:composition
160      * 
161      * @throws Exception
162      */
163     @Test
164     public void testComposition5() throws Exception {
165         /*
166         composition5.xhtml
167 
168         <ui:composition template="/composition5_1.xhtml">
169             composition5Content
170         </ui:composition>
171 
172         composition5_1.xhtml
173 
174         <ui:composition template="/composition5_2.xhtml">
175             start first composition
176             <ui:insert />
177             end first composition
178         </ui:composition>
179 
180         composition5_2.xhtml
181 
182         <ui:composition>      
183             start second composition
184             <ui:insert/>
185             end second composition
186         </ui:composition>
187 
188         Result
189 
190             start second composition
191             composition5Content
192             end second composition
193         */
194         
195         UIViewRoot root = facesContext.getViewRoot();
196         vdl.buildView(facesContext, root, "composition5.xhtml");
197         
198         StringWriter sw = new StringWriter();
199         MockResponseWriter mrw = new MockResponseWriter(sw);
200         facesContext.setResponseWriter(mrw);
201         root.encodeAll(facesContext);
202         sw.flush();
203         
204         String response = sw.toString();
205         Assert.assertFalse(response.contains("THIS SHOULD NOT BE RENDERED"));
206         
207         response = checkStringInOrder(response, "start second composition");
208         response = checkStringInOrder(response, "composition5Content");
209         response = checkStringInOrder(response, "end second composition");        
210     }
211     
212     private String checkStringInOrder(String response, String token)
213     {
214         int pos = response.indexOf(token);
215         Assert.assertTrue(pos > -1);
216         return response.substring(pos+token.length());
217     }
218     
219     
220     /**
221      * An ui:define on the outer most composition takes precedence over
222      * the inner one.
223      * 
224      * @throws Exception
225      */
226     @Test
227     public void testCompositionNested1() throws Exception {
228         /*
229 
230         compositionNested1.xhtml
231 
232         <ui:composition template="/composition4.xhtml">
233         <ui:define name="fragment1">
234         fragmentNumber2
235         </ui:define>
236         </ui:composition>
237 
238         composition4.xhtml
239 
240         <ui:composition template="/template1.xhtml">
241         <ui:define name="fragment1">
242         fragmentNumber1
243         </ui:define>
244         </ui:composition>
245 
246         template1.xhtml
247 
248         <ui:composition>
249         <ui:insert>
250         This fragment will not be inserted
251         </ui:insert>
252         <ui:insert name="fragment1">
253         fragmentNumber1
254         </ui:insert>
255         </ui:composition>
256 
257         Response
258 
259         fragmentNumber2
260 
261          */
262 
263         UIViewRoot root = facesContext.getViewRoot();
264         vdl.buildView(facesContext, root, "compositionNested1.xhtml");
265         
266         StringWriter sw = new StringWriter();
267         MockResponseWriter mrw = new MockResponseWriter(sw);
268         facesContext.setResponseWriter(mrw);
269         root.encodeAll(facesContext);
270         sw.flush();
271         
272         String response = sw.toString();
273         Assert.assertTrue(response.contains("fragmentNumber2"));
274         Assert.assertFalse(response.contains("fragmentNumber1"));
275         Assert.assertFalse(response.contains("This fragment will not be inserted"));
276         Assert.assertFalse(response.contains("THIS SHOULD NOT BE RENDERED"));
277     }
278     
279     @Test
280     public void testCompositionNested2() throws Exception
281     {
282         /*
283         
284         compositeNested2.xhtml
285         
286         <ui:composition template="/compositionNested2_1.xhtml">
287           <ui:define name="fragment1">
288             compositionNested2Content
289           </ui:define>
290         </ui:composition>
291       
292         compositeNested2_1.xhtml
293         
294         <ui:composition>
295             start first decoration
296             <ui:decorate template="/compositionNested2_2.xhtml">
297               <ui:define name="fragment1">
298                 start inner text
299                   <ui:insert name="fragment1"/>
300                 end inner text
301               </ui:define>
302             </ui:decorate>
303             end first decoration
304         </ui:composition>
305             
306         compositeNested2_2.xhtml
307         
308         <ui:composition>
309           start second composition
310             <ui:insert name="fragment1"/>
311           end second composition
312         </ui:composition>
313         
314         Response
315 
316             start first decoration
317             start second composition
318             start inner text
319             compositionNested2Content
320             end inner text
321             end second composition
322             end first decoration
323         */
324       
325         UIViewRoot root = facesContext.getViewRoot();
326         vdl.buildView(facesContext, root, "compositionNested2.xhtml");
327         
328         StringWriter sw = new StringWriter();
329         MockResponseWriter mrw = new MockResponseWriter(sw);
330         facesContext.setResponseWriter(mrw);
331         root.encodeAll(facesContext);
332         sw.flush();
333         
334         String response = sw.toString();
335         Assert.assertFalse(response.contains("THIS SHOULD NOT BE RENDERED"));
336         
337         response = checkStringInOrder(response, "start first decoration");
338         response = checkStringInOrder(response, "start second composition");
339         response = checkStringInOrder(response, "start inner text");
340         response = checkStringInOrder(response, "compositionNested2Content");
341         response = checkStringInOrder(response, "end inner text");
342         response = checkStringInOrder(response, "end second composition");
343         response = checkStringInOrder(response, "end first decoration");
344     }
345 }