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