1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.test.wysiwyg

File ListTest.java

 

Code metrics

0
397
43
1
929
584
43
0.11
9.23
43
1

Classes

Class Line # Actions
ListTest 32 397 0% 43 77
0.82582.5%
 

Contributing tests

This file is covered by 34 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.test.wysiwyg;
21   
22    import org.junit.Test;
23    import org.xwiki.test.wysiwyg.framework.AbstractWysiwygTestCase;
24   
25    /**
26    * Tests for the custom list support, to handle and generate valid XHTML lists in the wysiwyg. At the moment, this class
27    * tests processing the rendered lists rather than creating new lists from the wysiwyg, to ensure that valid rendered
28    * lists are managed correctly.
29    *
30    * @version $Id: 30489c78cfd9447583335b17d9f07f976c0c3b29 $
31    */
 
32    public class ListTest extends AbstractWysiwygTestCase
33    {
34    /**
35    * @see XWIKI-2734: Cannot edit the outer list item. The test is not deeply relevant as we are positioning the range
36    * programatically. The correct test would prove that the caret can be positioned there with the keys.
37    */
 
38  1 toggle @Test
39    public void testEmptyListItemsEditable()
40    {
41  1 switchToSource();
42  1 setSourceText("** rox");
43  1 switchToWysiwyg();
44    // Check that a br is added in the parent list item so that it becomes editable
45  1 assertContent("<ul><li><br><ul><li>rox</li></ul></li></ul>");
46    // Place the caret in the first list item
47  1 moveCaret("document.body.firstChild.firstChild", 0);
48  1 typeText("x");
49  1 assertContent("<ul><li>x<br><ul><li>rox</li></ul></li></ul>");
50    }
51   
52    /**
53    * Test the case when hitting enter in a list item before a sublist, that it creates an editable list item under.
54    * The test is not deeply relevant since we are positioning the range in the item under programatically. The correct
55    * test would prove that the caret can be positioned there with the keys.
56    */
 
57  1 toggle @Test
58    public void testEnterBeforeSublist()
59    {
60  1 switchToSource();
61  1 setSourceText("* x\n** rox");
62  1 switchToWysiwyg();
63  1 moveCaret("document.body.firstChild.firstChild.firstChild", 1);
64  1 typeEnter();
65    // Check the created item is editable
66  1 assertContent("<ul><li>x</li><li><br><ul><li>rox</li></ul></li></ul>");
67  1 moveCaret("document.body.firstChild.childNodes[1]", 0);
68  1 typeText("w");
69  1 assertContent("<ul><li>x</li><li>w<br><ul><li>rox</li></ul></li></ul>");
70    }
71   
72    /**
73    * Test the midas bug which causes the list items in a list to be replaced with an empty list and the caret to be
74    * left inside the ul, not editable.
75    */
 
76  1 toggle @Test
77    public void testEnterOnEntireList()
78    {
79  1 switchToSource();
80  1 setSourceText("* foo\n* bar");
81  1 switchToWysiwyg();
82    // Set the selection around the list
83  1 select("document.body.firstChild.firstChild.firstChild", 0, "document.body.firstChild.lastChild.firstChild", 3);
84  1 typeEnter();
85  1 typeText("x");
86  1 assertContent("<p><br></p>x");
87    }
88   
89    /**
90    * Test delete works fine inside a list item, and before another element (such as bold).
91    */
 
92  1 toggle @Test
93    public void testDeleteInsideItem()
94    {
95  1 switchToSource();
96  1 setSourceText("* foo**bar**\n** far");
97  1 switchToWysiwyg();
98    // Set the selection inside the foo text
99  1 moveCaret("document.body.firstChild.firstChild.firstChild", 1);
100  1 typeDelete();
101  1 assertContent("<ul><li>fo<strong>bar</strong><ul><li>far</li></ul></li></ul>");
102   
103    // set the selection just before the bold text but inside the text before
104  1 moveCaret("document.body.firstChild.firstChild.firstChild", 2);
105  1 typeDelete();
106  1 assertContent("<ul><li>fo<strong>ar</strong><ul><li>far</li></ul></li></ul>");
107    }
108   
109    /**
110    * Test backspace works fine inside a list item, and after another element (such as italic).
111    */
 
112  1 toggle @Test
113    public void testBackspaceInsideItem()
114    {
115  1 switchToSource();
116  1 setSourceText("* foo\n** b//arf//ar");
117  1 switchToWysiwyg();
118    // Set the selection in the "ar" text in the second list item
119  1 moveCaret("document.body.firstChild.firstChild.lastChild.firstChild.lastChild", 1);
120  1 typeBackspace();
121  1 assertContent("<ul><li>foo<ul><li>b<em>arf</em>r</li></ul></li></ul>");
122    // delete again, now it should delete inside the em
123  1 typeBackspace();
124  1 assertContent("<ul><li>foo<ul><li>b<em>ar</em>r</li></ul></li></ul>");
125    }
126   
127    /**
128    * Test that the delete at the end of the list works fine
129    */
 
130  1 toggle @Test
131    public void testDeleteInSameList()
132    {
133  1 switchToSource();
134  1 setSourceText("* foo\n* bar");
135  1 switchToWysiwyg();
136    // Set the selection at the end of the first item
137  1 moveCaret("document.body.firstChild.firstChild.firstChild", 3);
138  1 typeDelete();
139  1 assertContent("<ul><li>foobar</li></ul>");
140    }
141   
142    /**
143    * Test that the backspace at the beginning of the second item in a list moves the items together in the first list
144    * item.
145    */
 
146  1 toggle @Test
147    public void testBackspaceInSameList()
148    {
149  1 switchToSource();
150  1 setSourceText("* foo\n* bar");
151  1 switchToWysiwyg();
152    // Set the selection at the end of the first item
153  1 moveCaret("document.body.firstChild.lastChild.firstChild", 0);
154  1 typeBackspace();
155  1 assertContent("<ul><li>foobar</li></ul>");
156    }
157   
158    /**
159    * Test that delete at the end of a list preserves browser default behaviour: for firefox is to join the two lists. <br>
160    * TODO: re-activate when https://bugzilla.mozilla.org/show_bug.cgi?id=519751 will be fixed
161    */
 
162  0 toggle public void failingTestDeleteInDifferentLists()
163    {
164  0 switchToSource();
165  0 setSourceText("* foo\n\n* bar");
166  0 switchToWysiwyg();
167    // Set the selection at the end of the first item
168  0 moveCaret("document.body.firstChild.firstChild.firstChild", 3);
169  0 typeDelete();
170  0 assertContent("<ul><li>foo</li><li>bar</li></ul>");
171    }
172   
173    /**
174    * Test that backspace at the beginning of a list preserves browser default behaviour: for firefox is to join the
175    * two lists.
176    */
 
177  1 toggle @Test
178    public void testBackspaceInDifferentLists()
179    {
180  1 switchToSource();
181  1 setSourceText("* foo\n\n* bar");
182  1 switchToWysiwyg();
183    // Set the selection at the end of the first item
184  1 moveCaret("document.body.lastChild.firstChild.firstChild", 0);
185  1 typeBackspace();
186  1 assertContent("<ul><li>foo</li><li>bar</li></ul>");
187    }
188   
189    /**
190    * Test that backspace at the beginning of a list after another list in an embedded document (two lists on the
191    * second level) preserves default behaviour: for firefox is to join the two lists.
192    */
 
193  1 toggle @Test
194    public void testBackspaceInEmbeddedDocumentDifferentLists()
195    {
196  1 switchToSource();
197  1 setSourceText("* foo\n* bar (((\n* foo 2\n1. bar 2)))");
198  1 switchToWysiwyg();
199  1 moveCaret("document.body.firstChild.childNodes[1].childNodes[1].childNodes[1].firstChild.firstChild", 0);
200  1 typeBackspace();
201  1 assertContent("<ul><li>foo</li><li>bar<div><ul><li>foo 2</li><li>bar 2</li></ul></div></li></ul>");
202    }
203   
204    /**
205    * Test that delete at the end of a list before another list in an embedded document (two lists on the second level)
206    * preserves default behaviour: for firefox is to join the two lists. <br>
207    * TODO: re-activate when https://bugzilla.mozilla.org/show_bug.cgi?id=519751 will be fixed
208    */
 
209  0 toggle public void failingTestDeleteInEmbeddedDocumentDifferentLists()
210    {
211  0 switchToSource();
212  0 setSourceText("* foo\n* bar (((\n1. foo 2\n* bar 2)))");
213  0 switchToWysiwyg();
214  0 moveCaret("document.body.firstChild.childNodes[1].childNodes[1].firstChild.firstChild.firstChild", 5);
215  0 typeDelete();
216  0 assertContent("<ul><li>foo</li><li>bar<div><ol><li>foo 2</li><li>bar 2</li></ol></div></li></ul>");
217    }
218   
 
219  1 toggle @Test
220    public void testBackspaceInEmbeddedDocumentList()
221    {
222  1 switchToSource();
223  1 setSourceText("* foo(((bar\n* foar)))");
224  1 switchToWysiwyg();
225  1 moveCaret("document.body.firstChild.firstChild.childNodes[1].childNodes[1].firstChild.firstChild", 0);
226  1 typeBackspace();
227  1 assertContent("<ul><li>foo<div><p>bar</p>foar</div></li></ul>");
228    }
229   
230    /**
231    * TODO: re-activate when https://bugzilla.mozilla.org/show_bug.cgi?id=519751 will be fixed
232    */
 
233  0 toggle public void failingTestBackspaceAndDeleteToMergeEmbeddedDocumentListAndParagraph()
234    {
235  0 switchToSource();
236  0 setSourceText("* foo(((bar\n* foar)))");
237  0 switchToWysiwyg();
238  0 moveCaret("document.body.firstChild.firstChild.childNodes[1].childNodes[1].firstChild.firstChild", 0);
239  0 typeBackspace();
240  0 typeDelete();
241  0 assertContent("<ul><li>foo<div><p>barfoar</p></div></li></ul>");
242    }
243   
244    /**
245    * TODO: re-activate when https://bugzilla.mozilla.org/show_bug.cgi?id=519751 will be fixed
246    */
 
247  0 toggle public void failingTestDeleteInEmbeddedDocumentList()
248    {
249  0 switchToSource();
250  0 setSourceText("* foo(((* bar\n\nfoar)))");
251  0 switchToWysiwyg();
252  0 moveCaret("document.body.firstChild.firstChild.childNodes[1].firstChild.firstChild.firstChild", 3);
253  0 typeDelete();
254  0 assertContent("<ul><li>foo<div><ul><li>barfoar</li></ul></div></li></ul>");
255    }
256   
257    /**
258    * Tests that the delete moves the first item on another level in the item in which is executed.
259    */
 
260  1 toggle @Test
261    public void testDeleteBeforeSublist()
262    {
263    // 1/ with only one item -> the sublist should be removed
264  1 switchToSource();
265  1 setSourceText("* foo\n** bar\n");
266  1 switchToWysiwyg();
267    // Set the selection at the end of the first item
268  1 moveCaret("document.body.firstChild.firstChild.firstChild", 3);
269  1 typeDelete();
270  1 assertContent("<ul><li>foobar</li></ul>");
271   
272    // 2/ with more than one item -> only the first item should be moved to the list above
273  1 switchToSource();
274  1 setSourceText("* foo\n** bar\n** far");
275  1 switchToWysiwyg();
276    // Set the selection at the end of the first item
277  1 moveCaret("document.body.firstChild.firstChild.firstChild", 3);
278  1 typeDelete();
279  1 assertContent("<ul><li>foobar<ul><li>far</li></ul></li></ul>");
280    }
281   
282    /**
283    * Test that backspace at the beginning of an item in a sublist moves the item in the list item before, on a lower
284    * list level.
285    */
 
286  1 toggle @Test
287    public void testBackspaceBeginSublist()
288    {
289    // 1/ with only one item -> the sublist should be deleted
290  1 switchToSource();
291  1 setSourceText("* foo\n** bar\n");
292  1 switchToWysiwyg();
293    // Set the selection at beginning of the first item in sublist
294  1 moveCaret("document.body.firstChild.firstChild.lastChild.firstChild.firstChild", 0);
295  1 typeBackspace();
296  1 assertContent("<ul><li>foobar</li></ul>");
297   
298    // 2/ with more than one item -> only the first item should be moved to the list above
299  1 switchToSource();
300  1 setSourceText("* foo\n** bar\n** far");
301  1 switchToWysiwyg();
302    // Set the selection at beginning of the first item in sublist
303  1 moveCaret("document.body.firstChild.firstChild.lastChild.firstChild.firstChild", 0);
304  1 typeBackspace();
305  1 assertContent("<ul><li>foobar<ul><li>far</li></ul></li></ul>");
306    }
307   
308    /**
309    * Test that deleting at the end of a list item with a sublist with another sublist inside, moves the first sublist
310    * and the elements on level 3 are moved to level 2.
311    */
 
312  1 toggle @Test
313    public void testDeleteDecreasesLevelWithEmptyItem()
314    {
315  1 switchToSource();
316  1 setSourceText("* foo\n*** bar\n");
317  1 switchToWysiwyg();
318    // Set the selection at beginning of the first item in sublist
319  1 moveCaret("document.body.firstChild.firstChild.firstChild", 3);
320  1 typeDelete();
321  1 assertContent("<ul><li>foo<br><ul><li>bar</li></ul></li></ul>");
322    }
323   
324    /**
325    * Test that hitting backspace at the beginning of a list item with a sublist moves this element in its parent list
326    * item and decreases the level of the subitems.
327    */
 
328  1 toggle @Test
329    public void testBackspaceDecreasesLevelWithEmptyItem()
330    {
331  1 switchToSource();
332  1 setSourceText("* foo\n*** bar\n");
333  1 switchToWysiwyg();
334    // Set the selection at beginning of the first item in sublist
335  1 moveCaret("document.body.firstChild.firstChild.lastChild.firstChild", 0);
336  1 typeBackspace();
337  1 assertContent("<ul><li>foo<br><ul><li>bar</li></ul></li></ul>");
338    }
339   
340    /**
341    * Test delete at the end of a sublist item on a higher level moves the list item on the lower level inside it.
342    *
343    * @see XWIKI-3114: Backspace is ignored at the beginning of a list item if the previous list item is on a lower
344    * level.
345    */
 
346  1 toggle @Test
347    public void testDeleteBeforePreviousLevelItem()
348    {
349  1 switchToSource();
350  1 setSourceText("* foo\n** bar\n* bar minus one");
351  1 switchToWysiwyg();
352    // Set the selection at the end of "bar"
353  1 moveCaret("document.body.firstChild.firstChild.lastChild.firstChild.firstChild", 3);
354  1 typeDelete();
355  1 assertContent("<ul><li>foo<ul><li>barbar minus one</li></ul></li></ul>");
356    }
357   
358    /**
359    * Test backspace at the beginning of a sublist item before a sublist moves the item on the lower level to the item
360    * on the higher level.
361    *
362    * @see XWIKI-3114: Backspace is ignored at the beginning of a list item if the previous list item is on a lower
363    * level.
364    */
 
365  1 toggle @Test
366    public void testBackspaceAfterPreviousLevelItem()
367    {
368  1 switchToSource();
369  1 setSourceText("* foo\n** bar\n* bar minus one");
370  1 switchToWysiwyg();
371    // Set the selection at the end of "bar"
372  1 moveCaret("document.body.firstChild.lastChild.firstChild", 0);
373  1 typeBackspace();
374  1 assertContent("<ul><li>foo<ul><li>barbar minus one</li></ul></li></ul>");
375    }
376   
377    /**
378    * Test deleting the last piece of text inside a list item with sublists, keeps the remaining list item empty but
379    * editable. The test is weak, since we position the range programatically. The true test should try to navigate to
380    * the list item.
381    */
 
382  1 toggle @Test
383    public void testDeleteAllTextInListItem()
384    {
385  1 switchToSource();
386  1 setSourceText("* foo\n* b\n** ar");
387  1 switchToWysiwyg();
388   
389    // Set the selection at the beginning of the text in the second list item
390  1 moveCaret("document.body.firstChild.lastChild.firstChild", 0);
391  1 typeDelete();
392    // test that the list structure is correct: two items one with a sublist
393  1 assertContent("<ul><li>foo</li><li><br><ul><li>ar</li></ul></li></ul>");
394    // type in the empty list item
395  1 moveCaret("document.body.firstChild.lastChild", 0);
396  1 typeText("x");
397  1 assertContent("<ul><li>foo</li><li>x<br><ul><li>ar</li></ul></li></ul>");
398    // now delete, to test that it jumps the <br>
399  1 typeDelete();
400  1 assertContent("<ul><li>foo</li><li>xar</li></ul>");
401    }
402   
403    /**
404    * Test backspacing the last piece of text inside a list item with sublists, keeps the remaining list item empty but
405    * editable. The test is weak, since we position the range programatically. The true test should try to navigate to
406    * the list item.
407    */
 
408  1 toggle @Test
409    public void testBackspaceAllTextInListItem()
410    {
411  1 switchToSource();
412  1 setSourceText("* foo\n* b\n** ar");
413  1 switchToWysiwyg();
414   
415    // Set the selection at the end of the text in the second list item
416  1 moveCaret("document.body.firstChild.lastChild.firstChild", 1);
417  1 typeBackspace();
418    // test that the list structure is correct: two items one with a sublist
419  1 assertContent("<ul><li>foo</li><li><br><ul><li>ar</li></ul></li></ul>");
420    // type in the empty list item
421  1 moveCaret("document.body.firstChild.lastChild", 0);
422  1 typeText("x");
423  1 assertContent("<ul><li>foo</li><li>x<br><ul><li>ar</li></ul></li></ul>");
424    // Put the caret at the beginning of the sublist
425  1 moveCaret("document.body.firstChild.lastChild.lastChild.firstChild.firstChild", 0);
426    // now backspace, to test that it jumps the <br>
427  1 typeBackspace();
428  1 assertContent("<ul><li>foo</li><li>xar</li></ul>");
429    }
430   
431    /**
432    * Test delete before text outside lists. <br>
433    * TODO: re-activate when https://bugzilla.mozilla.org/show_bug.cgi?id=519751 will be fixed
434    */
 
435  0 toggle public void failingTestDeleteBeforeParagraph()
436    {
437  0 switchToSource();
438  0 setSourceText("* one\n* two\n\nFoobar");
439  0 switchToWysiwyg();
440   
441    // Set the selection at the end of the "two" list item
442  0 moveCaret("document.body.firstChild.lastChild.firstChild", 3);
443  0 typeDelete();
444  0 assertContent("<ul><li>one</li><li>twoFoobar</li></ul>");
445   
446    // now run the case with delete in a sublist
447  0 switchToSource();
448  0 setSourceText("* one\n** two\n\nFoobar");
449  0 switchToWysiwyg();
450   
451    // Set the selection at the end of the "two" list item
452  0 moveCaret("document.body.firstChild.firstChild.lastChild.firstChild.firstChild", 3);
453  0 typeDelete();
454  0 assertContent("<ul><li>one<ul><li>twoFoobar</li></ul></li></ul>");
455    }
456   
457    /**
458    * Test backspace at the beginning of list item, after text outside lists.
459    */
 
460  1 toggle @Test
461    public void testBackspaceAfterParagraph()
462    {
463  1 switchToSource();
464  1 setSourceText("Foobar\n\n* one\n* two");
465  1 switchToWysiwyg();
466   
467    // Set the selection at the beginning of the "one" list item
468  1 moveCaret("document.body.lastChild.firstChild.firstChild", 0);
469  1 typeBackspace();
470  1 assertContent("<p>Foobarone</p><ul><li>two</li></ul>");
471   
472    // Now test the case when the list has a sublist, in which case FF keeps the sublist parent, as empty and
473    // editable
474    // Note that this behaves differently on Internet Explorer, unwrapping the sublist
475  1 switchToSource();
476  1 setSourceText("Foobar\n\n* one\n** two");
477  1 switchToWysiwyg();
478   
479    // Set the selection at the beginning of the "one" list item
480  1 moveCaret("document.body.lastChild.firstChild.firstChild", 0);
481  1 typeBackspace();
482  1 assertContent("<p>Foobarone</p><ul><li><br><ul><li>two</li></ul></li></ul>");
483    }
484   
485    /**
486    * Test deleting the whole selection on a list, on multiple list levels keeps the list valid. Test that the parents
487    * of the indented list items that stay are editable.
488    */
 
489  1 toggle @Test
490    public void testDeleteSelectionPreserveSublists()
491    {
492  1 switchToSource();
493  1 setSourceText("* one\n** two\n** three\n*** four\n*** five");
494  1 switchToWysiwyg();
495   
496    // Set the selection starting in the one element and ending in the four element
497  1 select("document.body.firstChild.firstChild.firstChild", 2,
498    "document.body.firstChild.firstChild.lastChild.lastChild.lastChild.firstChild.firstChild", 2);
499  1 typeDelete();
500  1 assertContent("<ul><li>onur<ul><li><br><ul><li>five</li></ul></li></ul></li></ul>");
501    }
502   
503    /**
504    * Test deleting the whole selection on a list, on multiple list levels deletes all the fully enclosed list items
505    * and lists, and keeps the result in a single list item if the selection ends are on the same list level.
506    */
 
507  1 toggle @Test
508    public void testDeleteSelectionDeletesEnclosedSublists()
509    {
510  1 switchToSource();
511  1 setSourceText("* one\n** two\n** three\n*** four\n** five\n* six");
512  1 switchToWysiwyg();
513   
514    // Set the selection starting in the one element and ending in the six element
515  1 select("document.body.firstChild.firstChild.firstChild", 2, "document.body.firstChild.lastChild.firstChild", 1);
516  1 typeDelete();
517  1 assertContent("<ul><li>onix</li></ul>");
518    }
519   
520    /**
521    * Test creating a list with two items and indenting the second item. The indented item should be a sublist of the
522    * first item and the resulted HTML should be valid.
523    */
 
524  1 toggle @Test
525    public void testIndentNoSublist()
526    {
527  1 typeText("1");
528  1 clickUnorderedListButton();
529  1 typeEnter();
530  1 typeText("2");
531  1 assertContent("<ul><li>1</li><li>2<br></li></ul>");
532    // The indent tool bar button is disabled when the caret is not inside a list. We have to wait for the indent
533    // tool bar button to become enabled because the tool bar is updated with delay.
534  1 waitForPushButton(TOOLBAR_BUTTON_INDENT_TITLE, true);
535  1 clickIndentButton();
536  1 assertContent("<ul><li>1<ul><li>2<br></li></ul></li></ul>");
537    // test that the indented item cannot be indented once more
538  1 waitForPushButton(TOOLBAR_BUTTON_INDENT_TITLE, false);
539  1 moveCaret("document.body.firstChild.firstChild.childNodes[1].firstChild.firstChild", 0);
540  1 typeTab();
541    // check that nothing happened
542  1 assertContent("<ul><li>1<ul><li>2<br></li></ul></li></ul>");
543   
544  1 switchToSource();
545  1 assertSourceText("* 1\n** 2");
546    }
547   
548    /**
549    * Test that indenting an item to the second level under a list item with a list already on the second level unifies
550    * the two lists.
551    */
 
552  1 toggle @Test
553    public void testIndentUnderSublist()
554    {
555  1 typeText("1");
556  1 clickUnorderedListButton();
557  1 typeEnter();
558  1 typeTextThenEnter("2");
559  1 typeTab();
560  1 typeTextThenEnter("+");
561  1 typeShiftTab();
562  1 typeText("3");
563  1 waitForPushButton(TOOLBAR_BUTTON_INDENT_TITLE, true);
564  1 clickIndentButton();
565  1 assertContent("<ul><li>1</li><li>2<ul><li>+</li><li>3<br></li></ul></li></ul>");
566  1 switchToSource();
567  1 assertSourceText("* 1\n* 2\n** +\n** 3");
568    }
569   
570    /**
571    * Test indenting (using the tab key) an item with a sublist, that the child sublist is indented with its parent.
572    *
573    * @see XWIKI-3118: Indenting a list item with a sublist works incorrectly.
574    * @see XWIKI-3117: Shift + Tab does works incorrect on an item that contains a sublist.
575    */
 
576  1 toggle @Test
577    public void testIndentOutdentWithSublist()
578    {
579  1 typeText("1");
580  1 clickUnorderedListButton();
581  1 typeEnter();
582  1 typeText("2");
583    // The indent tool bar button is disabled when the caret is not inside a list. We have to wait for the indent
584    // tool bar button to become enabled because the tool bar is updated with delay.
585  1 waitForPushButton(TOOLBAR_BUTTON_INDENT_TITLE, true);
586  1 clickIndentButton();
587    // move to the end of the "1" element, hit enter, tab and type. Should create a new list item, parent of the "2"
588    // sublist, tab should indent and type should add content
589  1 moveCaret("document.body.firstChild.firstChild.firstChild", 1);
590  1 typeText("3");
591  1 moveCaret("document.body.firstChild.firstChild.firstChild", 1);
592  1 typeEnter();
593  1 assertContent("<ul><li>1</li><li>3<ul><li>2<br></li></ul></li></ul>");
594    // Check that the list item is indentable i.e. the list plugin is correctly recognizing lists (XWIKI-3061).
595    // The tool bar is not updated instantly and thus we have to wait for the indent button to become enabled.
596  1 waitForPushButton(TOOLBAR_BUTTON_INDENT_TITLE, true);
597  1 clickIndentButton();
598  1 assertContent("<ul><li>1<ul><li>3<ul><li>2<br></li></ul></li></ul></li></ul>");
599  1 switchToSource();
600  1 assertSourceText("* 1\n** 3\n*** 2");
601  1 switchToWysiwyg();
602    // select second element "3"
603  1 select("document.body.firstChild.firstChild.childNodes[1].firstChild.firstChild", 0,
604    "document.body.firstChild.firstChild.childNodes[1].firstChild.firstChild", 1);
605    // Check that the list item is outdentable i.e. the list plugin is correctly recognizing lists (XWIKI-3061).
606    // The tool bar is not updated instantly and thus we have to wait for the outdent button to become enabled.
607  1 waitForPushButton(TOOLBAR_BUTTON_OUTDENT_TITLE, true);
608  1 clickOutdentButton();
609  1 assertContent("<ul><li>1</li><li>3<ul><li>2<br></li></ul></li></ul>");
610  1 moveCaret("document.body.firstChild.childNodes[1].childNodes[1].firstChild.firstChild", 0);
611  1 clickOutdentButton();
612  1 assertContent("<ul><li>1</li><li>3</li><li>2<br></li></ul>");
613  1 switchToSource();
614  1 assertSourceText("* 1\n* 3\n* 2");
615    }
616   
617    /**
618    * Test outdenting an item on the first level in a list: it should split the list in two and put the content of the
619    * unindented item in between.
620    */
 
621  1 toggle @Test
622    public void testOutdentOnFirstLevel()
623    {
624  1 typeText("1");
625  1 clickUnorderedListButton();
626  1 typeEnter();
627  1 typeTextThenEnter("2");
628  1 typeTab();
629  1 typeTextThenEnter("+");
630  1 typeShiftTab();
631  1 typeText("3");
632    // move caret at the beginning of the "two" item
633  1 moveCaret("document.body.firstChild.childNodes[1].firstChild", 0);
634  1 typeShiftTab();
635  1 assertContent("<ul><li>1</li></ul><p>2</p><ul><li>+</li><li>3<br></li></ul>");
636  1 switchToSource();
637  1 assertSourceText("* 1\n\n2\n\n* +\n* 3");
638    }
639   
640    /**
641    * Test outdenting an item on the second level inside a list item which also contains content after the sublist
642    * correctly moves the content in the outdented list item.
643    */
 
644  1 toggle @Test
645    public void testOutdentWithContentAfter()
646    {
647  1 setContent("<ul><li>one<br>before<ul><li>two</li><li>three</li><li>four</li></ul>after</li></ul>");
648  1 moveCaret("document.body.firstChild.firstChild.childNodes[3].childNodes[1].firstChild", 0);
649    // The tool bar is not updated instantly and thus we have to wait for the outdent button to become enabled.
650  1 waitForPushButton(TOOLBAR_BUTTON_OUTDENT_TITLE, true);
651  1 clickOutdentButton();
652  1 assertContent("<ul><li>one<br>before<ul><li>two</li></ul></li><li>three<ul><li>four</li></ul>"
653    + "after</li></ul>");
654    }
655   
656    /**
657    * @see XWIKI-3447: List detection is reversed
658    */
 
659  1 toggle @Test
660    public void testListDetection()
661    {
662  1 switchToSource();
663  1 setSourceText("before\n\n" + "* unordered list item\n*1. ordered sub-list item\n\n"
664    + "1. ordered list item\n1*. unordered sub-list item");
665  1 switchToWysiwyg();
666   
667    // Outside lists
668  1 moveCaret("document.body.firstChild.firstChild", 3);
669  1 waitForOrderedListDetected(false);
670  1 waitForUnorderedListDetected(false);
671   
672    // Inside unordered list item
673  1 moveCaret("document.body.childNodes[1].firstChild.firstChild", 4);
674  1 waitForOrderedListDetected(false);
675  1 waitForUnorderedListDetected(true);
676    // Inside ordered sub-list item
677  1 moveCaret("document.body.childNodes[1].firstChild.lastChild.firstChild.firstChild", 7);
678  1 waitForOrderedListDetected(true);
679  1 waitForUnorderedListDetected(true);
680   
681    // Inside ordered list item
682  1 moveCaret("document.body.childNodes[2].firstChild.firstChild", 10);
683  1 waitForOrderedListDetected(true);
684  1 waitForUnorderedListDetected(false);
685    // Inside unordered sub-list item
686  1 moveCaret("document.body.childNodes[2].firstChild.lastChild.firstChild.firstChild", 9);
687  1 waitForOrderedListDetected(true);
688  1 waitForUnorderedListDetected(true);
689    }
690   
691    /**
692    * @see XWIKI-3773: Adding and editing lists in table cells.
693    */
 
694  1 toggle @Test
695    public void testCreateListInTableCell()
696    {
697  1 insertTable();
698  1 typeText("a");
699  1 clickUnorderedListButton();
700  1 typeEnter();
701  1 typeText("b");
702  1 switchToSource();
703  1 assertSourceText("|=(((\n* a\n* b\n)))|= \n| | ");
704    }
705   
706    /**
707    * Test indenting a list fragment by selecting all the items and hitting the indent button.
708    */
 
709  1 toggle @Test
710    public void testIndentListFragment()
711    {
712  1 switchToSource();
713  1 setSourceText("* one\n* two\n* three\n* three point one\n* three point two\n* three point three\n* four");
714  1 switchToWysiwyg();
715  1 select("document.body.firstChild.childNodes[3].firstChild", 0, "document.body.firstChild.childNodes[5].firstChild", 17);
716    // The tool bar is not updated instantly and thus we have to wait for the indent button to become enabled.
717  1 waitForPushButton(TOOLBAR_BUTTON_INDENT_TITLE, true);
718  1 clickIndentButton();
719  1 switchToSource();
720  1 assertSourceText("* one\n* two\n* three\n** three point one\n** three point two\n** three point three\n* four");
721    }
722   
723    /**
724    * Test the usual use case about only indenting the parent one level further, without its sublist. This cannot be
725    * done in one because it is not a correct indent, from a semantic point of view, but most users expect it to
726    * happen. The correct steps are to indent the parent and then outdent the sublist, which is the case tested by this
727    * function.
728    */
 
729  1 toggle @Test
730    public void testIndentParentWithNoSublist()
731    {
732  1 switchToSource();
733  1 setSourceText("* one\n* two\n* three\n** three point one\n** three point two\n** three point three\n* four");
734  1 switchToWysiwyg();
735  1 select("document.body.firstChild.childNodes[2].firstChild", 0, "document.body.firstChild.childNodes[2].firstChild", 5);
736    // The tool bar is not updated instantly and thus we have to wait for the indent button to become enabled.
737  1 waitForPushButton(TOOLBAR_BUTTON_INDENT_TITLE, true);
738  1 clickIndentButton();
739  1 select("document.body.firstChild.childNodes[1].childNodes[1].firstChild.childNodes[1].firstChild.firstChild", 0,
740    "document.body.firstChild.childNodes[1].childNodes[1].firstChild.childNodes[1].childNodes[2].firstChild", 17);
741    // The tool bar is not updated instantly and thus we have to wait for the outdent button to become enabled.
742  1 waitForPushButton(TOOLBAR_BUTTON_OUTDENT_TITLE, true);
743  1 clickOutdentButton();
744  1 switchToSource();
745  1 assertSourceText("* one\n* two\n** three\n** three point one\n** three point two\n** three point three\n* four");
746    }
747   
748    /**
749    * Tests indenting two items, amongst which one with a sublist and then outdenting the item with the sublist.
750    */
 
751  1 toggle @Test
752    public void testIndentItemWithSublistAndOutdent()
753    {
754  1 switchToSource();
755  1 setSourceText("* one\n* two\n* three\n** foo\n** bar\n* four\n* four\n* five");
756  1 switchToWysiwyg();
757  1 select("document.body.firstChild.childNodes[2].firstChild", 0, "document.body.firstChild.childNodes[3].firstChild", 4);
758    // The tool bar is not updated instantly and thus we have to wait for the indent button to become enabled.
759  1 waitForPushButton(TOOLBAR_BUTTON_INDENT_TITLE, true);
760  1 clickIndentButton();
761  1 switchToSource();
762  1 assertSourceText("* one\n* two\n** three\n*** foo\n*** bar\n** four\n* four\n* five");
763  1 switchToWysiwyg();
764  1 select("document.body.firstChild.childNodes[1].childNodes[1].firstChild.firstChild", 0,
765    "document.body.firstChild.childNodes[1].childNodes[1].firstChild.childNodes[1].childNodes[1].firstChild", 3);
766    // The tool bar is not updated instantly and thus we have to wait for the outdent button to become enabled.
767  1 waitForPushButton(TOOLBAR_BUTTON_OUTDENT_TITLE, true);
768  1 clickOutdentButton();
769  1 switchToSource();
770  1 assertSourceText("* one\n* two\n* three\n** foo\n** bar\n** four\n* four\n* five");
771    }
772   
773    /**
774    * Tests a few indent and outdent operations on a list inside an embedded document (in this case, a table cell),
775    * preceded by another list in the previous table cell.
776    */
 
777  1 toggle @Test
778    public void testIndentOutdentInTableCell()
779    {
780  1 switchToSource();
781  1 setSourceText("|(((* item 1\n* item 2)))|(((* one\n** one plus one\n** one plus two\n* two\n* three)))\n| | ");
782  1 switchToWysiwyg();
783  1 select(
784    "document.body.firstChild.firstChild.firstChild.childNodes[1].firstChild.firstChild.firstChild.childNodes[1]."
785    + "childNodes[1].firstChild", 0,
786    "document.body.firstChild.firstChild.firstChild.childNodes[1].firstChild.firstChild.childNodes[1]."
787    + "firstChild", 3);
788    // The tool bar is not updated instantly and thus we have to wait for the indent button to become enabled.
789  1 waitForPushButton(TOOLBAR_BUTTON_INDENT_TITLE, true);
790  1 clickIndentButton();
791  1 switchToSource();
792  1 assertSourceText("|(((\n* item 1\n* item 2\n)))"
793    + "|(((\n* one\n** one plus one\n*** one plus two\n** two\n* three\n)))\n| | ");
794  1 switchToWysiwyg();
795  1 select(
796    "document.body.firstChild.firstChild.firstChild.childNodes[1].firstChild.firstChild.firstChild.childNodes[1]."
797    + "childNodes[1].firstChild", 0,
798    "document.body.firstChild.firstChild.firstChild.childNodes[1].firstChild.firstChild.childNodes[1]."
799    + "firstChild", 5);
800    // The tool bar is not updated instantly and thus we have to wait for the outdent button to become enabled.
801  1 waitForPushButton(TOOLBAR_BUTTON_OUTDENT_TITLE, true);
802  1 clickOutdentButton();
803  1 switchToSource();
804  1 assertSourceText("|(((\n* item 1\n* item 2\n)))"
805    + "|(((\n* one\n** one plus one\n*** one plus two\n* two\n\nthree\n)))\n| | ");
806    }
807   
808    /**
809    * Test that outdenting multiple list items on the first level of a list preserves distinct lines for the content of
810    * the list items.
811    * <p>
812    * See http://jira.xwiki.org/jira/browse/XWIKI-3921.
813    */
 
814  1 toggle @Test
815    public void testOutdentFirstLevelPreservesLines()
816    {
817  1 switchToSource();
818  1 setSourceText("* one\n* two\n* three\n** three plus one\n"
819    + "* four\n* (((before\n* inner five\n* inner five + 1\n\nafter)))\n* six");
820  1 switchToWysiwyg();
821  1 select("document.body.firstChild.firstChild.firstChild", 0, "document.body.firstChild.childNodes[5].firstChild", 3);
822    // The tool bar is not updated instantly and thus we have to wait for the outdent button to become enabled.
823  1 waitForPushButton(TOOLBAR_BUTTON_OUTDENT_TITLE, true);
824  1 clickOutdentButton();
825  1 switchToSource();
826  1 assertSourceText("one\n\ntwo\n\nthree\n\n* three plus one\n\nfour\n\n"
827    + "(((\nbefore\n\n* inner five\n* inner five + 1\n\nafter\n)))\n\nsix");
828    }
829   
830    /**
831    * Tests that a backspace between two list items with headings inside moves the second heading in the first list
832    * item.
833    * <p>
834    * See http://jira.xwiki.org/jira/browse/XWIKI-3877.
835    */
 
836  1 toggle @Test
837    public void testBackspaceBetweenHeadingListItems()
838    {
839  1 typeText("abc");
840  1 clickUnorderedListButton();
841  1 applyStyleTitle1();
842  1 moveCaret("document.body.firstChild.firstChild.firstChild.firstChild", 2);
843  1 typeEnter();
844  1 typeBackspace();
845    // expecting a single list item, with 2 headings
846  1 assertContent("<ul><li><h1>ab</h1><h1>c</h1></li></ul>");
847  1 switchToSource();
848  1 assertSourceText("* (((\n= ab =\n\n= c =\n)))");
849    }
850   
851    /**
852    * Tests that the headings in two list items can be merged by a backspace followed by a delete: only one backspace,
853    * as the previous test shows, is not enough because two items of the same type should not be automatically merged
854    * on backspace between list items, since it's not the desired behaviour for all types of elements. <br>
855    * TODO: re-activate when https://bugzilla.mozilla.org/show_bug.cgi?id=519751 will be fixed
856    * <p>
857    * See http://jira.xwiki.org/jira/browse/XWIKI-3877.
858    */
 
859  0 toggle public void failingTestBackspaceAndDeleteToMergeHeadingListItems()
860    {
861    // split the previous test in 2 so that this one can be marked as failing
862    // now try to reunite two heading list items, with a backspace and a delete
863  0 typeText("abc");
864  0 clickUnorderedListButton();
865  0 applyStyleTitle1();
866  0 moveCaret("document.body.firstChild.firstChild.firstChild.firstChild", 2);
867  0 typeEnter();
868  0 typeBackspace();
869  0 typeDelete();
870    // expecting a single list item, with 2 headings
871  0 assertContent("<ul><li><h1>abc</h1></li></ul>");
872  0 switchToSource();
873  0 assertSourceText("* (((\n= abc =\n)))");
874    }
875   
876    /**
877    * Tests that a delete between two list items with headings inside moves the second heading in the first list item. <br>
878    * TODO: re-activate when https://bugzilla.mozilla.org/show_bug.cgi?id=519751 will be fixed
879    *
880    * See http://jira.xwiki.org/jira/browse/XWIKI-3877.
881    */
 
882  0 toggle public void failingTestDeleteBetweenHeadingListItems()
883    {
884  0 typeText("cba");
885  0 clickUnorderedListButton();
886  0 applyStyleTitle1();
887  0 moveCaret("document.body.firstChild.firstChild.firstChild.firstChild", 2);
888  0 typeEnter();
889  0 moveCaret("document.body.firstChild.firstChild.firstChild.firstChild", 2);
890  0 typeDelete();
891    // expecting a single list item, with 2 headings
892  0 assertContent("<ul><li><h1>cb</h1><h1>a</h1></li></ul>");
893  0 switchToSource();
894  0 assertSourceText("* (((\n= cb =\n\n= a =\n)))");
895   
896  0 setSourceText("");
897  0 switchToWysiwyg();
898   
899    // now try to reunite the two, with 2 deletes
900  0 typeText("cba");
901  0 clickUnorderedListButton();
902  0 applyStyleTitle1();
903  0 moveCaret("document.body.firstChild.firstChild.firstChild.firstChild", 2);
904  0 typeEnter();
905  0 moveCaret("document.body.firstChild.firstChild.firstChild.firstChild", 2);
906  0 typeDelete();
907  0 typeDelete();
908    // expecting a single list item, with 2 headings
909  0 assertContent("<ul><li><h1>cba</h1></li></ul>");
910  0 switchToSource();
911  0 assertSourceText("* (((\n= cba =\n)))");
912    }
913   
914    /**
915    * Waits for the editor to detect if the current selection is inside an ordered list.
916    */
 
917  5 toggle public void waitForOrderedListDetected(boolean down)
918    {
919  5 waitForToggleButtonState("Numbering On/Off", down);
920    }
921   
922    /**
923    * Waits for the editor to detect is the current selection is inside an unordered list.
924    */
 
925  5 toggle public void waitForUnorderedListDetected(boolean down)
926    {
927  5 waitForToggleButtonState("Bullets On/Off", down);
928    }
929    }