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

File MacroTest.java

 

Code metrics

2
729
82
1
1,876
1,095
85
0.12
8.89
82
1.04

Classes

Class Line # Actions
MacroTest 39 729 0% 85 5
0.9938499399.4%
 

Contributing tests

This file is covered by 50 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.openqa.selenium.By;
24    import org.openqa.selenium.Keys;
25    import org.openqa.selenium.TimeoutException;
26    import org.openqa.selenium.WebDriver;
27    import org.openqa.selenium.support.ui.ExpectedCondition;
28    import org.xwiki.test.wysiwyg.framework.AbstractWysiwygTestCase;
29   
30    import com.thoughtworks.selenium.Wait;
31   
32    import static org.junit.Assert.*;
33   
34    /**
35    * Integration tests for macro support inside the WYSIWYG editor.
36    *
37    * @version $Id: 506e0760409c0c1845c448d6c5f178aabfffb2ae $
38    */
 
39    public class MacroTest extends AbstractWysiwygTestCase
40    {
41    public static final String MENU_MACRO = "Macro";
42   
43    public static final String MENU_REFRESH = "Refresh";
44   
45    public static final String MENU_COLLAPSE = "Collapse";
46   
47    public static final String MENU_COLLAPSE_ALL = "Collapse All";
48   
49    public static final String MENU_EXPAND = "Expand";
50   
51    public static final String MENU_EXPAND_ALL = "Expand All";
52   
53    public static final String MENU_EDIT = "Edit Macro Properties...";
54   
55    public static final String MENU_INSERT = "Insert Macro...";
56   
57    public static final String MACRO_CATEGORY_SELECTOR = "//select[@title='Select a macro category']";
58   
59    public static final String MACRO_LIVE_FILTER_SELECTOR = "//input[@title = 'Type to filter']";
60   
61    public static final String MACRO_SELECTOR_LIST = "//div[contains(@class, 'xListBox')]";
62   
63    /**
64    * Tests that after deleting the last character before a macro the caret remains before the macro and not inside the
65    * macro.
66    */
 
67  1 toggle @Test
68    public void testDeleteCharacterBeforeMacro()
69    {
70  1 switchToSource();
71  1 setSourceText("a{{html}}b{{/html}}");
72  1 switchToWysiwyg();
73  1 typeDelete();
74  1 typeText("x");
75  1 switchToSource();
76  1 assertSourceText("x{{html}}b{{/html}}");
77    }
78   
79    /**
80    * Tests that by holding the Delete key down before a macro the caret doesn't get inside the macro, but, instead,
81    * the macro is deleted.
82    */
 
83  1 toggle @Test
84    public void testHoldDeleteKeyBeforeMacro()
85    {
86  1 switchToSource();
87  1 setSourceText("bc{{html}}def{{/html}}g");
88  1 switchToWysiwyg();
89    // Place the caret between "b" and "c".
90  1 moveCaret("document.body.firstChild.firstChild", 1);
91  1 typeDelete(2, true);
92  1 typeText("x");
93  1 switchToSource();
94  1 assertSourceText("bxg");
95    }
96   
97    /**
98    * Tests that after deleting with Backspace a text selection ending before a macro the caret remains before the
99    * macro and not inside the macro.
100    */
 
101  1 toggle @Test
102    public void testSelectCharacterBeforeMacroAndPressBackspace()
103    {
104  1 switchToSource();
105  1 setSourceText("g{{html}}h{{/html}}");
106  1 switchToWysiwyg();
107    // Select the character preceding the macro.
108  1 selectNode("document.body.firstChild.firstChild");
109  1 typeBackspace();
110  1 typeText("x");
111  1 switchToSource();
112  1 assertSourceText("x{{html}}h{{/html}}");
113    }
114   
115    /**
116    * Tests that if we select the text before a macro and insert a symbol instead of it then the symbol is inserted
117    * before the macro and not inside the macro.
118    */
 
119  1 toggle @Test
120    public void testSelectCharacterBeforeMacroAndInsertSymbol()
121    {
122  1 switchToSource();
123  1 setSourceText("i{{html}}j{{/html}}");
124  1 switchToWysiwyg();
125    // Select the character preceding the macro.
126  1 selectNode("document.body.firstChild.firstChild");
127  1 clickSymbolButton();
128  1 getSelenium().click("//div[@title='copyright sign']");
129  1 typeText("x");
130  1 switchToSource();
131  1 assertSourceText("\u00A9x{{html}}j{{/html}}");
132    }
133   
134    /**
135    * Tests that a macro can be deleted by pressing Delete key when the caret is placed before that macro.
136    */
 
137  1 toggle @Test
138    public void testPressDeleteJustBeforeMacro()
139    {
140  1 switchToSource();
141  1 setSourceText("j{{html}}k{{/html}}l");
142  1 switchToWysiwyg();
143    // Move the caret just before the macro.
144  1 moveCaret("document.body.firstChild.firstChild", 1);
145  1 typeDelete();
146  1 typeText("x");
147  1 switchToSource();
148  1 assertSourceText("jxl");
149    }
150   
151    /**
152    * Tests that after deleting the last character after a macro the caret remains after the macro and not inside the
153    * macro.
154    */
 
155  1 toggle @Test
156    public void testDeleteCharacterAfterMacro()
157    {
158  1 switchToSource();
159  1 setSourceText("a{{html}}b{{/html}}c");
160  1 switchToWysiwyg();
161    // Move the caret at the end.
162  1 moveCaret("document.body.firstChild.lastChild", 1);
163  1 typeBackspace();
164  1 typeText("x");
165  1 switchToSource();
166  1 assertSourceText("a{{html}}b{{/html}}x");
167    }
168   
169    /**
170    * Tests that by holding the Backspace key down after a macro the caret doesn't get inside the macro, but, instead,
171    * the macro is deleted.
172    */
 
173  1 toggle @Test
174    public void testHoldBackspaceKeyAfterMacro()
175    {
176  1 switchToSource();
177  1 setSourceText("c{{html}}def{{/html}}g");
178  1 switchToWysiwyg();
179    // Move the caret at the end.
180  1 moveCaret("document.body.firstChild.lastChild", 1);
181  1 typeBackspace(2, true);
182  1 typeText("x");
183  1 switchToSource();
184  1 assertSourceText("cx");
185    }
186   
187    /**
188    * Tests that after deleting with Delete key a text selection starting after a macro the caret remains after the
189    * macro and not inside the macro.
190    */
 
191  1 toggle @Test
192    public void testSelectCharacterAfterMacroAndPressDelete()
193    {
194  1 switchToSource();
195  1 setSourceText("g{{html}}h{{/html}}i");
196  1 switchToWysiwyg();
197    // Select the character following the macro.
198  1 selectNode("document.body.firstChild.lastChild");
199  1 typeDelete();
200  1 typeText("x");
201  1 switchToSource();
202  1 assertSourceText("g{{html}}h{{/html}}x");
203    }
204   
205    /**
206    * Tests that if we select the text after a macro and insert a symbol instead of it then the symbol is inserted
207    * after the macro and not inside the macro.
208    */
 
209  1 toggle @Test
210    public void testSelectCharacterAfterMacroAndInsertSymbol()
211    {
212  1 switchToSource();
213  1 setSourceText("i{{html}}j{{/html}}k");
214  1 switchToWysiwyg();
215    // Select the character following the macro.
216  1 selectNode("document.body.firstChild.lastChild");
217  1 clickSymbolButton();
218  1 getSelenium().click("//div[@title='copyright sign']");
219  1 typeText("x");
220  1 switchToSource();
221  1 assertSourceText("i{{html}}j{{/html}}\u00A9x");
222    }
223   
224    /**
225    * Tests that a macro can be deleted by pressing Backspace key when the caret is placed after that macro.
226    */
 
227  1 toggle @Test
228    public void testPressBackspaceJustAfterMacro()
229    {
230  1 switchToSource();
231  1 setSourceText("k{{html}}l{{/html}}m");
232  1 switchToWysiwyg();
233    // Move the caret at the end.
234  1 moveCaret("document.body.firstChild.lastChild", 0);
235  1 typeBackspace();
236  1 typeText("x");
237  1 switchToSource();
238  1 assertSourceText("kxm");
239    }
240   
241    /**
242    * Tests that Undo/Redo operations don't affect the macros present in the edited document.
243    */
 
244  1 toggle @Test
245    public void testUndoRedoWhenMacrosArePresent()
246    {
247  1 switchToSource();
248  1 setSourceText("{{html}}pq{{/html}}");
249  1 switchToWysiwyg();
250    // We have to manually place the caret to be sure it is before the macro. The caret is before the macro when the
251    // browser window is focused but inside the macro when the tests run in background.
252  1 moveCaret("document.body", 0);
253  1 typeText("uv");
254  1 clickUndoButton();
255  1 clickRedoButton();
256  1 switchToSource();
257  1 assertSourceText("uv{{html}}pq{{/html}}");
258    }
259   
260    /**
261    * Clicks on a macro and deletes it.
262    */
 
263  1 toggle @Test
264    public void testSelectAndDeleteMacro()
265    {
266  1 switchToSource();
267  1 setSourceText("{{html}}<p>foo</p>{{/html}}\n\nbar");
268  1 switchToWysiwyg();
269  1 selectRichTextAreaFrame();
270  1 try {
271  1 getSelenium().click(getMacroLocator(0));
272    } finally {
273  1 selectTopFrame();
274    }
275  1 typeBackspace();
276  1 switchToSource();
277  1 assertSourceText("bar");
278    }
279   
280    /**
281    * @see XWIKI-3221: New lines inside code macro are lost when saving
282    */
 
283  1 toggle @Test
284    public void testWhiteSpacesInsideCodeMacroArePreserved()
285    {
286  1 String wikiText = "{{code}}\nfunction foo() {\n alert('bar');\n}\n{{/code}}";
287  1 switchToSource();
288  1 setSourceText(wikiText);
289  1 switchToWysiwyg();
290  1 switchToSource();
291  1 assertSourceText(wikiText);
292    }
293   
294    /**
295    * Test if the user can collapse and expand all the macros using the macro menu and if this menu is synchronized
296    * with the current state of the rich text area.
297    */
 
298  1 toggle @Test
299    public void testCollapseAndExpandAllMacros()
300    {
301  1 setContent("no macro");
302   
303  1 clickMenu(MENU_MACRO);
304  1 assertTrue(isMenuEnabled(MENU_REFRESH));
305    // If there's no macro present then the Collapse/Expand menu items must be disabled.
306  1 assertFalse(isMenuEnabled(MENU_COLLAPSE_ALL));
307  1 assertFalse(isMenuEnabled(MENU_EXPAND_ALL));
308  1 closeMenuContaining(MENU_REFRESH);
309   
310  1 switchToSource();
311  1 setSourceText("k\n\n{{html}}l{{/html}}\n\nm\n\n{{code}}n{{/code}}\n\no");
312  1 switchToWysiwyg();
313  1 clickMenu(MENU_MACRO);
314    // By default all macros are expanded.
315  1 assertTrue(isMenuEnabled(MENU_COLLAPSE_ALL));
316  1 assertFalse(isMenuEnabled(MENU_EXPAND_ALL));
317   
318    // Let's collapse all macros.
319  1 clickMenu(MENU_COLLAPSE_ALL);
320   
321  1 clickMenu(MENU_MACRO);
322    // Now all macros should be collapsed.
323  1 assertFalse(isMenuEnabled(MENU_COLLAPSE_ALL));
324  1 assertTrue(isMenuEnabled(MENU_EXPAND_ALL));
325   
326    // Let's expand all macros.
327  1 clickMenu(MENU_EXPAND_ALL);
328   
329  1 clickMenu(MENU_MACRO);
330    // Now all macros should be expanded.
331  1 assertTrue(isMenuEnabled(MENU_COLLAPSE_ALL));
332  1 assertFalse(isMenuEnabled(MENU_EXPAND_ALL));
333  1 closeMenuContaining(MENU_REFRESH);
334   
335    // Let's collapse the first macro by selecting it first and then using the shortcut key.
336  1 selectMacro(0);
337  1 collapseMacrosUsingShortcutKey();
338    // Finally unselect the macro.
339  1 clearMacroSelection();
340   
341    // Now let's check the menu. Both Collapse All and Expand All menu items should be enabled.
342  1 clickMenu(MENU_MACRO);
343  1 assertTrue(isMenuEnabled(MENU_COLLAPSE_ALL));
344  1 assertTrue(isMenuEnabled(MENU_EXPAND_ALL));
345    }
346   
347    /**
348    * Test if the user can collapse and expand the selected macros using the macro menu and if this menu is
349    * synchronized with the current state of the rich text area.
350    */
 
351  1 toggle @Test
352    public void testCollapseAndExpandSelectedMacros()
353    {
354  1 switchToSource();
355  1 setSourceText("o\n\n{{html}}n{{/html}}\n\nm\n\n{{code}}l{{/code}}\n\nk");
356  1 switchToWysiwyg();
357   
358    // If no macro is selected then Expand and Collapse menu entries shouldn't be present.
359  1 clickMenu(MENU_MACRO);
360  1 assertTrue(isMenuEnabled(MENU_REFRESH));
361  1 assertFalse(isMenuEnabled(MENU_COLLAPSE));
362  1 assertFalse(isMenuEnabled(MENU_EXPAND));
363  1 closeMenuContaining(MENU_REFRESH);
364   
365    // Select the first macro and collapse it (by default macros should be expanded).
366  1 selectMacro(0);
367  1 clickMenu(MENU_MACRO);
368  1 assertTrue(isMenuEnabled(MENU_COLLAPSE));
369  1 assertFalse(isMenuEnabled(MENU_EXPAND));
370  1 clickMenu(MENU_COLLAPSE);
371   
372    // Now expand it back.
373  1 clickMenu(MENU_MACRO);
374  1 assertFalse(isMenuEnabled(MENU_COLLAPSE));
375  1 assertTrue(isMenuEnabled(MENU_EXPAND));
376  1 clickMenu(MENU_EXPAND);
377   
378    // Let's select the second macro too.
379  1 getSelenium().controlKeyDown();
380  1 selectMacro(1);
381  1 getSelenium().controlKeyUp();
382   
383    // Collapse both selected macros.
384  1 clickMenu(MENU_MACRO);
385  1 assertTrue(isMenuEnabled(MENU_COLLAPSE));
386  1 assertFalse(isMenuEnabled(MENU_EXPAND));
387  1 clickMenu(MENU_COLLAPSE);
388   
389    // Let's check if the menu reports them as collapsed.
390  1 clickMenu(MENU_MACRO);
391  1 assertFalse(isMenuEnabled(MENU_COLLAPSE));
392  1 assertTrue(isMenuEnabled(MENU_EXPAND));
393   
394    // Expand both.
395  1 clickMenu(MENU_EXPAND);
396   
397    // Let's check if the menu reports them as expanded.
398  1 clickMenu(MENU_MACRO);
399  1 assertTrue(isMenuEnabled(MENU_COLLAPSE));
400  1 assertFalse(isMenuEnabled(MENU_EXPAND));
401  1 closeMenuContaining(MENU_COLLAPSE);
402    }
403   
404    /**
405    * Test if the user can select a macro by clicking it and then toggle between collapsed and expanded states using
406    * the space key.
407    */
 
408  1 toggle @Test
409    public void testClickToSelectMacroAndToggleCollapse()
410    {
411    // Let's use a macro without definition.
412  1 switchToSource();
413  1 setSourceText("{{foo}}bar{{/foo}}");
414  1 switchToWysiwyg();
415   
416    // By default macros are expanded. Let's check this.
417    // Note: We have to select the rich text area frame because the visibility of an element is evaluated relative
418    // to the current window.
419  1 selectRichTextAreaFrame();
420  1 try {
421  1 assertFalse(getSelenium().isVisible(getMacroPlaceHolderLocator(0)));
422  1 assertTrue(getSelenium().isVisible(getMacroOutputLocator(0)));
423    } finally {
424  1 selectTopFrame();
425    }
426   
427    // Select the macro.
428  1 selectMacro(0);
429   
430    // Let's collapse the selected macro and check its state.
431  1 toggleMacroCollapsedState();
432  1 selectRichTextAreaFrame();
433  1 try {
434  1 assertTrue(getSelenium().isVisible(getMacroPlaceHolderLocator(0)));
435  1 assertFalse(getSelenium().isVisible(getMacroOutputLocator(0)));
436    } finally {
437  1 selectTopFrame();
438    }
439   
440    // Let's expand the selected macro and check its state.
441  1 toggleMacroCollapsedState();
442  1 selectRichTextAreaFrame();
443  1 try {
444  1 assertFalse(getSelenium().isVisible(getMacroPlaceHolderLocator(0)));
445  1 assertTrue(getSelenium().isVisible(getMacroOutputLocator(0)));
446    } finally {
447  1 selectTopFrame();
448    }
449    }
450   
451    /**
452    * Tests the refresh feature when there's no macro present in the edited document.
453    */
 
454  1 toggle @Test
455    public void testRefreshContentWithoutMacros()
456    {
457  1 String text = "a b";
458  1 typeText(text);
459  1 assertEquals(text, getRichTextArea().getText());
460   
461    // If no macros are present then the refresh shoudn't affect too much the edited content.
462  1 refreshMacros();
463  1 assertEquals(text, getRichTextArea().getText());
464    }
465   
466    /**
467    * Tests that the user can refresh all the macros from the edited document by using the Refresh menu.
468    */
 
469  1 toggle @Test
470    public void testRefreshMacros()
471    {
472  1 switchToSource();
473  1 setSourceText("{{box}}p{{/box}}\n\n{{code}}q{{/code}}");
474  1 switchToWysiwyg();
475   
476    // Collapse the second macro.
477  1 selectRichTextAreaFrame();
478  1 try {
479  1 assertFalse(getSelenium().isVisible(getMacroPlaceHolderLocator(1)));
480  1 assertTrue(getSelenium().isVisible(getMacroOutputLocator(1)));
481    } finally {
482  1 selectTopFrame();
483    }
484  1 selectMacro(1);
485  1 toggleMacroCollapsedState();
486  1 selectRichTextAreaFrame();
487  1 try {
488  1 assertTrue(getSelenium().isVisible(getMacroPlaceHolderLocator(1)));
489  1 assertFalse(getSelenium().isVisible(getMacroOutputLocator(1)));
490    } finally {
491  1 selectTopFrame();
492    }
493   
494    // Unselect the macro.
495  1 clearMacroSelection();
496   
497    // Refresh the content
498  1 refreshMacros();
499   
500    // Check if the second macro is expanded.
501  1 selectRichTextAreaFrame();
502  1 try {
503  1 assertFalse(getSelenium().isVisible(getMacroPlaceHolderLocator(1)));
504  1 assertTrue(getSelenium().isVisible(getMacroOutputLocator(1)));
505    } finally {
506  1 selectTopFrame();
507    }
508    }
509   
510    /**
511    * Tests that the user can refresh the Table Of Contents macro after adding more headers.
512    */
 
513  1 toggle @Test
514    public void testRefreshTocMacro()
515    {
516  1 switchToSource();
517  1 setSourceText("{{toc start=\"1\"/}}\n\n= Title 1\n\n== Title 2");
518  1 switchToWysiwyg();
519   
520    // We should have two list items in the edited document.
521  1 String listItemCountExpression = "return document.getElementsByTagName('li').length";
522  1 assertEquals(2L, getRichTextArea().executeScript(listItemCountExpression));
523   
524    // Place the caret after the second heading and insert a new one.
525  1 moveCaret("document.getElementsByTagName('h2')[0].firstChild.firstChild", 7);
526    // Wait for the macro to be unselected.
527  1 waitForSelectedMacroCount(0);
528  1 typeEnter();
529  1 typeText("Title 3");
530  1 applyStyleTitle3();
531   
532    // Refresh the content and the TOC macro.
533  1 refreshMacros();
534   
535    // We should have three list items in the edited document now.
536  1 assertEquals(3L, getRichTextArea().executeScript(listItemCountExpression));
537    }
538   
539    /**
540    * Tests the edit macro feature by editing a HTML macro instance and changing its content and a parameter.
541    */
 
542  1 toggle @Test
543    public void testEditHTMLMacro()
544    {
545  1 switchToSource();
546  1 setSourceText("{{html}}white{{/html}}");
547  1 switchToWysiwyg();
548  1 editMacro(0);
549   
550    // Change the content of the HTML macro.
551  1 setFieldValue("pd-content-input", "black");
552   
553    // Set the Wiki parameter to true.
554  1 getSelenium().select("pd-wiki-input", "yes");
555   
556    // Apply changes.
557  1 applyMacroChanges();
558   
559    // Test if our changes have been applied.
560  1 switchToSource();
561  1 assertSourceText("{{html wiki=\"true\"}}\nblack\n{{/html}}");
562  1 switchToWysiwyg();
563   
564    // Edit again, this time using the default value for the Wiki parameter.
565  1 editMacro(0);
566   
567    // Set the Wiki parameter to its default value, false.
568  1 assertEquals("true", getSelenium().getValue("pd-wiki-input"));
569  1 getSelenium().select("pd-wiki-input", "no");
570   
571    // Apply changes.
572  1 applyMacroChanges();
573   
574    // Test if our changes have been applied. This time the Wiki parameter is missing from the output because it has
575    // the default value.
576  1 switchToSource();
577  1 assertSourceText("{{html}}\nblack\n{{/html}}");
578    }
579   
580    /**
581    * Tests if the edit macro feature doesn't fail when the user inputs special characters like {@code "} (used for
582    * wrapping parameter values) or {@code |-|} (used to separate the macro name, parameter list and macro content in
583    * macro serialization).
584    *
585    * @see XWIKI-3270: Quotes inside macro parameter values need to be escaped
586    */
 
587  1 toggle @Test
588    public void testEditMacroWithSpecialCharactersInParameterValues()
589    {
590  1 switchToSource();
591  1 setSourceText("{{box title = \"1~\"2|-|3=~~~\"4~~\" }}=~\"|-|~~{{/box}}");
592  1 switchToWysiwyg();
593  1 editMacro(0);
594   
595    // Check if the content of the macro has the right value.
596  1 assertEquals("=~\"|-|~~", getSelenium().getValue("pd-content-input"));
597   
598    // Check if the title parameter has the right value (it should be the first text input).
599  1 assertEquals("1\"2|-|3=~\"4~", getSelenium().getValue("pd-title-input"));
600   
601    // Change the title parameter.
602  1 setFieldValue("pd-title-input", "a\"b|-|c=~\"d~");
603  1 applyMacroChanges();
604   
605  1 switchToSource();
606  1 assertSourceText("{{box title=\"a~\"b|-|c=~~~\"d~~\"}}\n=~\"|-|~~\n{{/box}}");
607    }
608   
609    /**
610    * Tests if the edit macro feature doesn't fail when the user tries to edit an unregistered macro (a macro who's
611    * descriptor can't be found).
612    */
 
613  1 toggle @Test
614    public void testEditUnregisteredMacro()
615    {
616  1 switchToSource();
617  1 setSourceText("{{foo}}bar{{/foo}}");
618  1 switchToWysiwyg();
619  1 editMacro(0);
620   
621    // Check if the dialog shows the error message
622  1 assertTrue(getSelenium().isVisible("//div[@class = 'xDialogBody']/div[contains(@class, 'errormessage')]"));
623    }
624   
625    /**
626    * Tests that macro edits can be undone.
627    */
 
628  1 toggle @Test
629    public void testUndoMacroEdit()
630    {
631  1 switchToSource();
632  1 setSourceText("{{velocity}}$xcontext.user{{/velocity}}");
633  1 switchToWysiwyg();
634   
635    // First edit.
636  1 editMacro(0);
637  1 setFieldValue("pd-content-input", "$datetool.date");
638  1 applyMacroChanges();
639   
640    // Second edit.
641  1 editMacro(0);
642  1 setFieldValue("pd-content-input", "$xwiki.version");
643  1 applyMacroChanges();
644   
645  1 waitForPushButton(TOOLBAR_BUTTON_UNDO_TITLE, true);
646  1 clickUndoButton(2);
647  1 waitForPushButton(TOOLBAR_BUTTON_REDO_TITLE, true);
648  1 clickRedoButton();
649  1 switchToSource();
650  1 assertSourceText("{{velocity}}\n$datetool.date\n{{/velocity}}");
651    }
652   
653    /**
654    * Tests the basic insert macro scenario, using the code macro.
655    */
 
656  1 toggle @Test
657    public void testInsertCodeMacro()
658    {
659  1 insertMacro("Code");
660   
661  1 setFieldValue("pd-content-input", "function f(x) {\n return x;\n}");
662  1 applyMacroChanges();
663   
664  1 editMacro(0);
665  1 setFieldValue("pd-title-input", "Identity function");
666  1 applyMacroChanges();
667   
668  1 switchToSource();
669  1 assertSourceText("{{code title=\"Identity function\"}}\nfunction f(x) {\n return x;\n}\n{{/code}}");
670    }
671   
672    /**
673    * Tests if the ToC macro can be inserted in an empty paragraph without receiving the "Not an inline macro" error
674    * message.
675    *
676    * @see XWIKI-3551: Cannot insert standalone macros
677    */
 
678  1 toggle @Test
679    public void testInsertTOCMacro()
680    {
681    // Create two headings to be able to detect if the ToC macro has the right output.
682  1 typeText("Title 1");
683  1 applyStyleTitle1();
684   
685  1 typeEnter();
686  1 typeText("Title 2");
687  1 applyStyleTitle2();
688   
689    // Let's insert a ToC macro between the two headings.
690    // First, place the caret at the end of first heading.
691  1 moveCaret("document.body.getElementsByTagName('h1')[0].firstChild", 7);
692    // Get out of the heading.
693  1 typeEnter();
694    // Insert the ToC macro
695  1 insertMacro("Table Of Contents");
696    // Make sure the ToC starts with level 2 headings.
697  1 setFieldValue("pd-start-input", "2");
698  1 applyMacroChanges();
699   
700    // Check the output of the ToC macro.
701  1 assertEquals(1L, getRichTextArea().executeScript("return document.getElementsByTagName('li').length"));
702   
703    // Check the XWiki syntax.
704  1 switchToSource();
705  1 assertSourceText("= Title 1 =\n\n\n{{toc start=\"2\"/}}\n\n\n== Title 2 ==");
706    }
707   
708    /**
709    * @see XWIKI-4048: Automatically add empty new line before/after macros when inserting standalone macros
710    */
 
711  1 toggle @Test
712    public void testInsertStandAloneMacroInline()
713    {
714  1 switchToSource();
715  1 setSourceText("= Heading =\n\nparagraph");
716  1 switchToWysiwyg();
717   
718    // Place the caret inside the paragraph.
719  1 moveCaret("document.body.lastChild.firstChild", 4);
720   
721    // Insert the ToC macro
722  1 insertMacro("Table Of Contents");
723  1 applyMacroChanges();
724   
725    // Check the output of the ToC macro.
726  1 assertEquals(1L, getRichTextArea().executeScript("return document.getElementsByTagName('li').length"));
727   
728    // Check the XWiki syntax.
729  1 switchToSource();
730  1 assertSourceText("= Heading =\n\npara\n\n{{toc/}}\n\ngraph");
731    }
732   
733    /**
734    * Inserts a HTML macro, whose output contains block-level elements, in the middle of a paragraph's text and tests
735    * if the macro can be fixed by separating it in an empty paragraph.
736    *
737    * @see XWIKI-3551: Cannot insert standalone macros
738    */
 
739  1 toggle @Test
740    public void testInsertHTMLMacroWithBlockContentInANotEmptyParagraph()
741    {
742    // Create a paragraph with some text inside.
743  1 typeText("beforeafter");
744  1 applyStyleTitle1();
745  1 applyStylePlainText();
746   
747    // Place the caret in the middle of the paragraph.
748  1 moveCaret("document.body.firstChild.firstChild", 6);
749   
750    // Insert the HTML macro.
751  1 insertMacro("HTML");
752    // Make the macro render a list, which is forbidden inside a paragraph.
753  1 setFieldValue("pd-content-input", "<ul><li>xwiki</li></ul>");
754  1 applyMacroChanges();
755   
756    // At this point the macro should render an error message instead of the list.
757  1 String listItemCountExpression = "return document.getElementsByTagName('li').length";
758  1 assertEquals(0L, getRichTextArea().executeScript(listItemCountExpression));
759   
760    // Let's fix the macro by separating it in an empty paragraph.
761    // Move the caret before the macro and press Enter to move it into a new paragraph.
762  1 moveCaret("document.body.firstChild.firstChild", 6);
763  1 typeEnter();
764    // Move the caret after the macro and press Enter to move the following text in a new paragraph.
765  1 moveCaret("document.body.lastChild.lastChild", 0);
766  1 typeEnter();
767   
768    // Now the macro should be in an empty paragraph.
769    // Let's refresh the content to see if the macro was fixed.
770  1 refreshMacros();
771    // Check the output of the HTML macro.
772  1 assertEquals(1L, getRichTextArea().executeScript(listItemCountExpression));
773   
774    // Check the XWiki syntax.
775  1 switchToSource();
776  1 assertSourceText("before\n\n{{html}}\n<ul><li>xwiki</li></ul>\n{{/html}}\n\nafter");
777    }
778   
779    /**
780    * @see XWIKI-3570: Code macro fails to escape properly in GWT editor
781    */
 
782  1 toggle @Test
783    public void testInsertCodeMacroWithXMLComments()
784    {
785    // Insert the Code macro.
786  1 insertMacro("Code");
787    // Set the language parameter to XML.
788  1 setFieldValue("pd-language-input", "xml");
789    // Set the content. Include XML comments in the content.
790  1 setFieldValue("pd-content-input",
791    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- this is a test -->\n<test>123</test>");
792  1 applyMacroChanges();
793   
794    // Check the XWiki syntax.
795  1 switchToSource();
796  1 assertSourceText("{{code language=\"xml\"}}\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
797    + "<!-- this is a test -->\n<test>123</test>\n{{/code}}");
798  1 switchToWysiwyg();
799   
800    // Edit the inserted macro.
801  1 editMacro(0);
802  1 assertEquals("xml", getSelenium().getValue("pd-language-input"));
803  1 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- this is a test -->\n<test>123</test>",
804    getSelenium().getValue("pd-content-input"));
805  1 closeDialog();
806    }
807   
808    /**
809    * @see XWIKI-3581: WYSIWYG editor treats macro parameter names as case sensitive
810    */
 
811  1 toggle @Test
812    public void testDetectMacroParameterNamesIgnoringCase()
813    {
814  1 switchToSource();
815  1 setSourceText("{{box CSSClaSS=\"foo\"}}bar{{/box}}");
816  1 switchToWysiwyg();
817    // Edit the Box macro.
818  1 editMacro(0);
819    // See if the CSSClaSS parameter was correctly detected.
820  1 assertEquals("foo", getSelenium().getValue("pd-cssClass-input"));
821    // Change the value of the CSSClaSS parameter.
822  1 setFieldValue("pd-cssClass-input", "xyz");
823  1 applyMacroChanges();
824    // Check the XWiki syntax.
825  1 switchToSource();
826  1 assertSourceText("{{box CSSClaSS=\"xyz\"}}\nbar\n{{/box}}");
827    }
828   
829    /**
830    * @see XWIKI-3735: Differentiate macros with empty content from macros without content.
831    */
 
832  1 toggle @Test
833    public void testDifferentiateMacrosWithEmptyContentFromMacrosWithoutContent()
834    {
835  1 StringBuffer macros = new StringBuffer();
836  1 macros.append("{{code/}}");
837  1 macros.append("{{code}}{{/code}}");
838  1 macros.append("{{code title=\"1|-|2\"/}}");
839  1 macros.append("{{code title=\"1|-|2\"}}{{/code}}");
840   
841    // Insert the macros.
842  1 switchToSource();
843  1 setSourceText(macros.toString());
844  1 switchToWysiwyg();
845    // See if the macro syntax is left unchanged when the macros are not edited.
846  1 switchToSource();
847  1 assertSourceText(macros.toString());
848  1 switchToWysiwyg();
849   
850    // Edit the first macro (the one without content and without arguments).
851  1 editMacro(0);
852  1 setFieldValue("pd-content-input", "|-|");
853  1 applyMacroChanges();
854  1 switchToSource();
855  1 assertSourceText("{{code}}|-|{{/code}}{{code}}{{/code}}{{code title=\"1|-|2\"/}}{{code title=\"1|-|2\"}}{{/code}}");
856  1 switchToWysiwyg();
857   
858    // Edit the second macro (the one with empty content but without arguments).
859  1 editMacro(1);
860  1 setFieldValue("pd-title-input", "|-|");
861  1 setFieldValue("pd-content-input", "|-|");
862  1 applyMacroChanges();
863   
864    // Edit the third macro (the one without content but with arguments).
865  1 editMacro(2);
866  1 setFieldValue("pd-title-input", "");
867  1 setFieldValue("pd-content-input", "|-|");
868  1 applyMacroChanges();
869   
870    // Edit the forth macro (the one with empty content and with arguments).
871  1 editMacro(3);
872  1 setFieldValue("pd-content-input", "|-|");
873  1 applyMacroChanges();
874   
875    // Check the result.
876  1 switchToSource();
877  1 assertSourceText("{{code}}|-|{{/code}}{{code title=\"|-|\"}}|-|{{/code}}"
878    + "{{code}}|-|{{/code}}{{code title=\"1|-|2\"}}|-|{{/code}}");
879    }
880   
881    /**
882    * @see XWIKI-4085: Content duplicated if i have a macro (toc, id..) in an html macro.
883    */
 
884  1 toggle @Test
885    public void testNestedMacrosAreNotDuplicated()
886    {
887  1 StringBuilder content = new StringBuilder();
888  1 content.append("{{html wiki=\"true\"}}\n\n");
889  1 content.append("= Hello title 1 =\n\n");
890  1 content.append("{{toc start=\"2\"/}}\n\n");
891  1 content.append("= Hello title 2 =\n\n");
892  1 content.append("{{/html}}");
893  1 switchToSource();
894  1 setSourceText(content.toString());
895  1 switchToWysiwyg();
896   
897    // Check if only one macro was detected (which should be the top level macro).
898  1 assertEquals(1, getMacroCount());
899   
900    // Check if the top level macro was correctly detected.
901  1 deleteMacro(0);
902  1 switchToSource();
903  1 assertSourceText("");
904   
905    // Reset the initial content.
906  1 setSourceText(content.toString());
907  1 switchToWysiwyg();
908   
909    // Check if the nested macro is duplicated.
910  1 switchToSource();
911  1 assertSourceText(content.toString());
912    }
913   
914    /**
915    * @see XWIKI-4155: Use double click or Enter to select the macro to insert.
916    */
 
917  1 toggle @Test
918    public void testDoubleClickToSelectMacroToInsert()
919    {
920  1 openSelectMacroDialog();
921   
922    // We have to wait for the specified macro to be displayed on the dialog because the loading indicator is
923    // removed just before the list of macros is displayed and the Selenium click command can interfere.
924  1 waitForMacroListItem("Info Message", true);
925    // Each double click event should be preceded by a click event.
926  1 getSelenium().click(getMacroListItemLocator("Info Message"));
927    // Fire the double click event.
928  1 getSelenium().doubleClick(getMacroListItemLocator("Info Message"));
929  1 waitForDialogToLoad();
930   
931    // Fill the macro content.
932  1 setFieldValue("pd-content-input", "x");
933  1 applyMacroChanges();
934   
935    // Check the result.
936  1 switchToSource();
937  1 assertSourceText("{{info}}\nx\n{{/info}}");
938    }
939   
940    /**
941    * @see XWIKI-4155: Use double click or Enter to select the macro to insert.
942    */
 
943  1 toggle @Test
944    public void testPressEnterToSelectMacroToInsert()
945    {
946  1 openSelectMacroDialog();
947   
948    // We have to wait for the specified macro to be displayed on the dialog because the loading indicator is
949    // removed just before the list of macros is displayed and the Selenium click command can interfere.
950  1 waitForMacroListItem("HTML", true);
951    // Select a macro.
952  1 getSelenium().click(getMacroListItemLocator("HTML"));
953    // Press Enter to choose the selected macro.
954  1 getSelenium().typeKeys("//div[@class = 'xListBox']", "\\13");
955  1 waitForDialogToLoad();
956   
957    // Fill the macro content.
958  1 setFieldValue("pd-content-input", "a");
959  1 applyMacroChanges();
960   
961    // Check the result.
962  1 switchToSource();
963  1 assertSourceText("{{html}}\na\n{{/html}}");
964    }
965   
966    /**
967    * @see XWIKI-4137: Pop up the "Edit macro properties" dialog when double-clicking on a macro block.
968    */
 
969  1 toggle @Test
970    public void testDoubleClickToEditMacro()
971    {
972    // Insert two macros.
973  1 switchToSource();
974  1 setSourceText("{{error}}x{{/error}}{{info}}y{{/info}}");
975  1 switchToWysiwyg();
976   
977    // Double click to edit the second macro.
978  1 selectRichTextAreaFrame();
979  1 try {
980  1 String infoMacroLocator = getMacroLocator(1);
981  1 waitForElement(infoMacroLocator);
982  1 getSelenium().doubleClick(infoMacroLocator);
983    } finally {
984  1 selectTopFrame();
985    }
986  1 waitForDialogToLoad();
987   
988    // Fill the macro content.
989  1 setFieldValue("pd-content-input", "z");
990  1 applyMacroChanges();
991   
992    // Check the result.
993  1 switchToSource();
994  1 assertSourceText("{{error}}x{{/error}}{{info}}z{{/info}}");
995    }
996   
997    /**
998    * Sometimes when you double click a macro the browser selects the macro container (i.e. the DOM selection wraps the
999    * element that contains the macro output). Test if the macro edit box is still triggered.
1000    */
 
1001  1 toggle @Test
1002    public void testDoubleClickToEditMacroWhenDOMSelectionWrapsTheMacroContainer()
1003    {
1004    // Insert a macro.
1005  1 switchToSource();
1006  1 setSourceText("before {{error}}currently{{/error}} after");
1007  1 switchToWysiwyg();
1008   
1009    // Double click to edit the macro.
1010  1 selectRichTextAreaFrame();
1011  1 try {
1012    // Fire the double click event on the macro.
1013  1 getSelenium().doubleClick(getMacroLocator(0));
1014    } finally {
1015  1 selectTopFrame();
1016    }
1017  1 waitForDialogToLoad();
1018   
1019    // Fill the macro content.
1020  1 setFieldValue("pd-content-input", "now");
1021  1 applyMacroChanges();
1022   
1023    // Check the result.
1024  1 switchToSource();
1025  1 assertSourceText("before {{error}}now{{/error}} after");
1026    }
1027   
1028    /**
1029    * @see XWIKI-6121: Double clicking on text makes macro edit box appear
1030    */
 
1031  1 toggle @Test
1032    public void testDoubleClickOutsideSelectedMacro()
1033    {
1034    // Insert a macro.
1035  1 switchToSource();
1036    // Put the outside text before the macro to overcome an issue in Selenium's MouseMoveAction.
1037    // See http://code.google.com/p/selenium/issues/detail?id=4863 (Move mouse action fails inside an iframe if the
1038    // x/y coordinates of the target element on the screen are greater than the width/height of the iframe)
1039  1 setSourceText("(% id=\"outside\" %)after\n\n{{info}}before{{/info}}");
1040  1 switchToWysiwyg();
1041   
1042    // Select the macro.
1043  1 selectMacro(0);
1044  1 waitForSelectedMacroCount(1);
1045   
1046    // Double click on the paragraph outside of the macro output.
1047  1 selectRichTextAreaFrame();
1048  1 try {
1049  1 getSelenium().doubleClick("document.getElementById('outside')");
1050    } finally {
1051  1 selectTopFrame();
1052    }
1053   
1054  1 try {
1055  1 waitForDialogToLoad();
1056  0 fail("The macro edit box shouldn't be triggered by double clicking outside of the macro output.");
1057    } catch (TimeoutException e) {
1058    // Expected.
1059    }
1060    }
1061   
1062    /**
1063    * @see XWIKI-3437: List macros by category/library
1064    */
 
1065  1 toggle @Test
1066    public void testSelectMacroFromCategory()
1067    {
1068  1 openSelectMacroDialog();
1069   
1070    // "All Macros" category should be selected by default.
1071  1 assertEquals("All Macros", getSelectedMacroCategory());
1072   
1073    // Make sure the "Code" and "Velocity" macros are present in "All Macros" category.
1074  1 waitForMacroListItem("Code", true);
1075  1 waitForMacroListItem("Velocity", true);
1076   
1077    // "Velocity" shouldn't be in the "Formatting" category.
1078  1 selectMacroCategory("Formatting");
1079  1 waitForMacroListItem("Code", true);
1080  1 waitForMacroListItem("Velocity", false);
1081   
1082    // "Code" shouldn't be in the "Development" category.
1083  1 selectMacroCategory("Development");
1084  1 waitForMacroListItem("Velocity", true);
1085  1 waitForMacroListItem("Code", false);
1086   
1087    // Select the "Velocity" macro.
1088  1 getSelenium().click(getMacroListItemLocator("Velocity"));
1089  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1090  1 waitForDialogToLoad();
1091   
1092    // Set the content field.
1093  1 setFieldValue("pd-content-input", "$xwiki.version");
1094  1 applyMacroChanges();
1095   
1096    // Open the "Select Macro" dialog again to see if its state was preserved.
1097  1 openSelectMacroDialog();
1098  1 assertEquals("Development", getSelectedMacroCategory());
1099  1 closeDialog();
1100   
1101    // Check the result.
1102  1 switchToSource();
1103  1 assertSourceText("{{velocity}}\n$xwiki.version\n{{/velocity}}");
1104    }
1105   
1106    /**
1107    * @see XWIKI-4206: Add the ability to search in the list of macros
1108    */
 
1109  1 toggle @Test
1110    public void testFilterMacrosFromCategory()
1111    {
1112  1 openSelectMacroDialog();
1113   
1114    // Make sure the current category is "All Macros".
1115  1 selectMacroCategory("All Macros");
1116   
1117    // Check if "Velocity", "Footnote" and "Error Message" macros are present.
1118  1 waitForMacroListItem("Velocity", true);
1119  1 waitForMacroListItem("Footnote", true);
1120  1 waitForMacroListItem("Error Message", true);
1121   
1122    // Check if the filter can make a difference.
1123  1 int expectedMacroCountAfterFilterAllMacros = getMacroListItemCount("note");
1124  1 assertTrue(expectedMacroCountAfterFilterAllMacros < getMacroListItemCount());
1125   
1126    // Filter the macros.
1127  1 filterMacrosContaining("note");
1128   
1129    // Check what macros are present.
1130  1 waitForMacroListItem("Velocity", false);
1131  1 waitForMacroListItem("Error Message", true);
1132   
1133    // Check the number of macros.
1134  1 assertEquals(expectedMacroCountAfterFilterAllMacros, getMacroListItemCount());
1135   
1136    // Check if the filter is preserved when switching the category.
1137    // Select the category of the "Footnote" macro.
1138  1 selectMacroCategory("Content");
1139  1 waitForMacroListItem("Footnote", true);
1140  1 waitForMacroListItem("Error Message", false);
1141    // Select the category of the "Error Message" macro.
1142  1 selectMacroCategory("Formatting");
1143  1 waitForMacroListItem("Error Message", true);
1144  1 waitForMacroListItem("Footnote", false);
1145   
1146    // Save the current macro list item count to be able to check if the filter state is preserved.
1147  1 int previousMacroListItemCount = getMacroListItemCount();
1148   
1149    // Select the "Error Message" macro.
1150  1 getSelenium().click(getMacroListItemLocator("Error Message"));
1151  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1152  1 waitForDialogToLoad();
1153   
1154    // Set the content field.
1155  1 setFieldValue("pd-content-input", "test");
1156  1 applyMacroChanges();
1157   
1158    // Open the "Select Macro" dialog again to see if the filter was preserved.
1159  1 openSelectMacroDialog();
1160  1 waitForMacroListItem("Error Message", true);
1161  1 assertEquals("note", getMacroFilterValue());
1162  1 assertEquals(previousMacroListItemCount, getMacroListItemCount());
1163  1 assertEquals(previousMacroListItemCount, getMacroListItemCount("note"));
1164  1 closeDialog();
1165   
1166    // Check the result.
1167  1 switchToSource();
1168  1 assertSourceText("{{error}}\ntest\n{{/error}}");
1169    }
1170   
1171    /**
1172    * @see XWIKI-3434: Use the dialog wizard for insert macro UI
1173    */
 
1174  1 toggle @Test
1175    public void testReturnToSelectMacroStep()
1176    {
1177  1 openSelectMacroDialog();
1178  1 waitForMacroListItem("Velocity", true);
1179   
1180    // Filter the macros.
1181  1 int scriptMacroCount = getMacroListItemCount("script");
1182  1 selectMacroCategory("Development");
1183  1 filterMacrosContaining("script");
1184  1 waitForMacroListItemCount(scriptMacroCount);
1185   
1186    // Select the "Groovy" macro.
1187  1 getSelenium().click(getMacroListItemLocator("Groovy"));
1188  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1189  1 waitForDialogToLoad();
1190   
1191    // Return to the "Select Macro" step.
1192  1 getSelenium().click("//div[@class = 'xDialogContent']//button[text() = 'Previous']");
1193  1 waitForDialogToLoad();
1194   
1195    // Check if the state of the "Select Macro" dialog was preserved.
1196  1 assertEquals("Development", getSelectedMacroCategory());
1197  1 assertEquals("script", getMacroFilterValue());
1198   
1199    // Select a different macro.
1200  1 waitForMacroListItem("Velocity", true);
1201  1 getSelenium().click(getMacroListItemLocator("Velocity"));
1202  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1203  1 waitForDialogToLoad();
1204   
1205    // Set the content field.
1206  1 setFieldValue("pd-content-input", "$xcontext.user");
1207  1 applyMacroChanges();
1208   
1209    // Check the result.
1210  1 switchToSource();
1211  1 assertSourceText("{{velocity}}\n$xcontext.user\n{{/velocity}}");
1212    }
1213   
1214    /**
1215    * Tests that the user can't move to the Edit Macro step without selection a macro first.
1216    */
 
1217  1 toggle @Test
1218    public void testValidateSelectMacroStep()
1219    {
1220  1 openSelectMacroDialog();
1221    // Wait for the list of macros to be filled.
1222  1 waitForMacroListItem("Velocity", true);
1223    // Make sure no macro is selected.
1224  1 assertFalse(isMacroListItemSelected());
1225    // The validation message should be hidden.
1226  1 assertFieldErrorIsNotPresent();
1227    // Try to move to the next step.
1228  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1229    // Check if the validation message is visible.
1230  1 assertFieldErrorIsPresent("Please select a macro from the list below.", MACRO_SELECTOR_LIST);
1231   
1232    // The validation message should be hidden when we change the macro category.
1233  1 selectMacroCategory("Navigation");
1234    // Wait for the list of macros to be updated (Velocity macro shouldn't be present in the updated list).
1235  1 waitForMacroListItem("Velocity", false);
1236    // Make sure no macro is selected.
1237  1 assertFalse(isMacroListItemSelected());
1238    // The validation message should be hidden.
1239  1 assertFieldErrorIsNotPresent();
1240    // Try to move to the next step.
1241  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1242    // Check if the validation message is visible.
1243  1 assertFieldErrorIsPresent("Please select a macro from the list below.", MACRO_SELECTOR_LIST);
1244   
1245    // The validation message should be hidden when we filter the macros.
1246  1 filterMacrosContaining("anchor");
1247    // Wait for the list of macros to be filtered. The ToC macro should be filtered out.
1248  1 waitForMacroListItem("Table Of Contents", false);
1249    // Make sure no macro is selected.
1250  1 assertFalse(isMacroListItemSelected());
1251    // The validation message should be hidden.
1252  1 assertFieldErrorIsNotPresent();
1253    // Try to move to the next step.
1254  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1255    // Check if the validation message is visible.
1256  1 assertFieldErrorIsPresent("Please select a macro from the list below.", MACRO_SELECTOR_LIST);
1257   
1258    // The validation message should be hidden when we cancel the dialog.
1259  1 closeDialog();
1260  1 openSelectMacroDialog();
1261  1 assertFieldErrorIsNotPresent();
1262    // Make sure no macro is selected.
1263  1 assertFalse(isMacroListItemSelected());
1264    // Try to move to the next step.
1265  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1266    // Check if the validation message is visible.
1267  1 assertFieldErrorIsPresent("Please select a macro from the list below.", MACRO_SELECTOR_LIST);
1268   
1269    // Finally select a macro.
1270  1 getSelenium().click(getMacroListItemLocator("Id"));
1271  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1272  1 waitForDialogToLoad();
1273   
1274    // The validation message shouldn't be visible (we moved to the next step).
1275  1 assertFieldErrorIsNotPresent();
1276   
1277    // Set the name field.
1278  1 setFieldValue("pd-name-input", "foo");
1279  1 applyMacroChanges();
1280   
1281    // Check the result.
1282  1 switchToSource();
1283  1 assertSourceText("{{id name=\"foo\"/}}");
1284    }
1285   
1286    /**
1287    * Tests if the user can select from the previously inserted macros.
1288    */
 
1289  1 toggle @Test
1290    public void testSelectFromPreviouslyInsertedMacros()
1291    {
1292  1 openSelectMacroDialog();
1293   
1294    // The "Previously Inserted Macros" category should be initially empty.
1295  1 selectMacroCategory("Previously Inserted Macros");
1296  1 waitForMacroListItemCount(0);
1297   
1298    // Insert a macro to see if it appears under the "Previously Inserted Macros" category.
1299  1 selectMacroCategory("All Macros");
1300  1 waitForMacroListItem("HTML", true);
1301  1 getSelenium().click(getMacroListItemLocator("HTML"));
1302  1 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1303  1 waitForDialogToLoad();
1304  1 setFieldValue("pd-content-input", "xwiki");
1305  1 applyMacroChanges();
1306   
1307    // Check if the inserted macro is listed under the "Previously Inserted Macros" category.
1308  1 openSelectMacroDialog();
1309  1 selectMacroCategory("Previously Inserted Macros");
1310    // Wait for the macro list to be updated.
1311  1 waitForMacroListItemCount(1);
1312    // Velocity macro shouldn't be present among the previously used macros.
1313  1 assertFalse(getDriver().hasElementWithoutWaiting(By.xpath(getMacroListItemLocator("Velocity"))));
1314  1 assertTrue(getDriver().hasElementWithoutWaiting(By.xpath(getMacroListItemLocator("HTML"))));
1315   
1316    // Close the dialog and check the result.
1317  1 closeDialog();
1318  1 switchToSource();
1319  1 assertSourceText("{{html}}\nxwiki\n{{/html}}");
1320    }
1321   
1322    /**
1323    * @see XWIKI-4415: Context document not set when refreshing macros.
1324    */
 
1325  1 toggle @Test
1326    public void testRefreshContextSensitiveVelocity()
1327    {
1328  1 switchToSource();
1329  1 setSourceText("{{velocity}}$doc.fullName{{/velocity}}");
1330  1 switchToWysiwyg();
1331  1 String expected = getRichTextArea().getText();
1332  1 refreshMacrosUsingShortcutKey();
1333  1 assertEquals(expected, getRichTextArea().getText());
1334    }
1335   
1336    /**
1337    * @see XWIKI-4541: Links are removed when a macro is collapsed and the editor looses focus.
1338    */
 
1339  1 toggle @Test
1340    public void testLinksArePreservedWhenMacroIsCollapsed()
1341    {
1342  1 switchToSource();
1343  1 setSourceText("before\n\n{{velocity}}abc [[123>>http://www.xwiki.org]] xyz{{/velocity}}\n\nafter");
1344  1 switchToWysiwyg();
1345    // Make sure the rich text area is focused. We need to do this to be sure the blur event has any effect.
1346  1 focusRichTextArea();
1347    // Check if the link is present before collapsing the macro.
1348  1 String linkCountExpression = "return document.getElementsByTagName('a').length";
1349  1 assertEquals(1L, getRichTextArea().executeScript(linkCountExpression));
1350    // Select the macro.
1351  1 selectMacro(0);
1352    // Collapse the macro.
1353  1 toggleMacroCollapsedState();
1354    // Blur and focus again the rich text area.
1355  1 blurRichTextArea();
1356  1 focusRichTextArea();
1357    // Expand the macro.
1358  1 toggleMacroCollapsedState();
1359    // The link should have been preserved.
1360  1 assertEquals(1L, getRichTextArea().executeScript(linkCountExpression));
1361    }
1362   
1363    /**
1364    * @see XWIKI-4613: Macros that output STYLE tags inside the HTML body generate wiki syntax garbage.
1365    */
 
1366  1 toggle @Test
1367    public void testHTMLMacroWithStyleTag()
1368    {
1369  1 switchToSource();
1370  1 StringBuilder sourceText = new StringBuilder();
1371  1 sourceText.append("{{html clean=\"false\"}}\n");
1372  1 sourceText.append("<style type=\"text/css\">\n");
1373  1 sourceText.append(".test {\n");
1374  1 sourceText.append(" color: red;\n");
1375  1 sourceText.append("}\n");
1376  1 sourceText.append("</style>\n");
1377  1 sourceText.append("<div class=\"test\">This is a test.</div>\n");
1378  1 sourceText.append("{{/html}}");
1379  1 setSourceText(sourceText.toString());
1380  1 switchToWysiwyg();
1381    // Force re-rendering.
1382  1 refreshMacrosUsingShortcutKey();
1383    // Check the result.
1384  1 switchToSource();
1385  1 assertSourceText(sourceText.toString());
1386    }
1387   
1388    /**
1389    * @see XWIKI-4856: Charset errors on macro insertion
1390    */
 
1391  1 toggle @Test
1392    public void testMacroWithUnicodeCharacters()
1393    {
1394    // Insert a macro with Unicode characters.
1395  1 switchToSource();
1396  1 String sourceText = "before {{info}}\u0103\u0219\u021B\u00E2\u00EE\u00E9\u00E8{{/info}} after";
1397  1 setSourceText(sourceText);
1398  1 switchToWysiwyg();
1399    // Do a round-trip to the server to re-parse and re-render the content.
1400  1 refreshMacros();
1401    // Check if the content is affected by undo operation.
1402  1 typeText("1 2");
1403  1 waitForPushButton(TOOLBAR_BUTTON_UNDO_TITLE, true);
1404  1 clickUndoButton(2);
1405    // Check the result.
1406  1 switchToSource();
1407  1 assertSourceText("1" + sourceText);
1408    }
1409   
1410    /**
1411    * @see XWIKI-4946: Default values for the required macro parameters should be send to the server by the WYSIWYG
1412    */
 
1413  1 toggle @Test
1414    public void testDefaultValuesForMandatoryParametersAreSent()
1415    {
1416  1 open(this.getClass().getSimpleName(), getTestMethodName(), "edit", "editor=object");
1417  1 if (!isElementPresent("xclass_XWiki.WikiMacroClass")) {
1418    // Create the macro.
1419  1 getSelenium().select("classname", "WikiMacroClass");
1420  1 clickEditAddObject();
1421  1 setFieldValue("XWiki.WikiMacroClass_0_id", "now");
1422  1 setFieldValue("XWiki.WikiMacroClass_0_name", "Now");
1423  1 getSelenium().select("XWiki.WikiMacroClass_0_contentType", "No content");
1424  1 setFieldValue("XWiki.WikiMacroClass_0_code", "{{velocity}}$datetool.date{{/velocity}}");
1425  1 clickEditSaveAndContinue();
1426    // Create the mandatory parameter.
1427  1 getSelenium().select("classname", "WikiMacroParameterClass");
1428  1 clickEditAddObject();
1429  1 setFieldValue("XWiki.WikiMacroParameterClass_0_name", "format");
1430  1 getSelenium().select("XWiki.WikiMacroParameterClass_0_mandatory", "Yes");
1431  1 setFieldValue("XWiki.WikiMacroParameterClass_0_defaultValue", "yyyy.MM.dd");
1432  1 clickEditSaveAndContinue();
1433    }
1434  1 open(this.getClass().getSimpleName(), getTestMethodName(), "edit", "editor=wysiwyg");
1435  1 waitForEditorToLoad();
1436    // Insert the macro we just created.
1437  1 insertMacro("Now");
1438  1 applyMacroChanges();
1439    // Check the result.
1440  1 switchToSource();
1441  1 assertSourceText("{{now format=\"yyyy.MM.dd\"/}}");
1442    }
1443   
1444    /**
1445    * @see XWIKI-5013: HTML code visible when inserting velocity macro displaying a property
1446    */
 
1447  1 toggle @Test
1448    public void testInsertVelocityMacroDisplayingAProperty()
1449    {
1450  1 insertMacro("Velocity");
1451  1 setFieldValue("pd-content-input", "$xwiki.getDocument(\"XWiki.Admin\").display(\"comment\")");
1452  1 applyMacroChanges();
1453    // Check the displayed text.
1454    // Trim the white-space that is coming from the macro selection boundary and which is not visible by the user.
1455    // There's also some white-space generate by the elements that wrap or follow the text area.
1456  1 assertEquals("Admin is the default Wiki Admin.", getRichTextArea().getText().trim());
1457    }
1458   
1459    /**
1460    * Tests that a macro can be inserted by clicking the associated tool bar button.
1461    */
 
1462  1 toggle @Test
1463    public void testInsertMacroFromToolBar()
1464    {
1465    // The tool bar button for inserting the velocity macro has been added in WysiwygTestSetup.
1466  1 clickInsertMacroButton("velocity");
1467  1 waitForDialogToLoad();
1468  1 setFieldValue("pd-content-input", "$xwiki.version");
1469  1 applyMacroChanges();
1470    // Check if the macro was correctly inserted.
1471  1 switchToSource();
1472  1 assertSourceText("{{velocity}}\n$xwiki.version\n{{/velocity}}");
1473    }
1474   
1475    /**
1476    * @see XWIKI-4461: Cannot have a cursor around macro blocks in Wysiwyg
1477    * @see XWIKI-3335: Cannot move the caret with the right arrow key after a macro ending the document
1478    */
 
1479  1 toggle @Test
1480    public void testTypeAroundMacro()
1481    {
1482  1 switchToSource();
1483  1 setSourceText("{{info}}one{{/info}}{{warning}}two{{/warning}}{{error}}three{{/error}}"
1484    + "\n\n{{info}}four{{/info}}\n\n{{warning}}five{{/warning}}");
1485  1 switchToWysiwyg();
1486   
1487    // Place the caret at the start of the first macro.
1488  1 moveCaret(getMacroOutputLocator(0) + ".firstChild.firstChild", 0);
1489  1 typeText("1");
1490   
1491    // Place the caret at the end of the first macro.
1492  1 moveCaret(getMacroOutputLocator(0) + ".firstChild.firstChild", 3);
1493  1 typeText(" ");
1494    // Check that Space didn't toggle the macro collapsed state.
1495    // Note: We have to select the rich text area frame because the visibility of an element is evaluated relative
1496    // to the current window.
1497  1 selectRichTextAreaFrame();
1498  1 try {
1499  1 assertFalse(getSelenium().isVisible(getMacroPlaceHolderLocator(0)));
1500  1 assertTrue(getSelenium().isVisible(getMacroOutputLocator(0)));
1501    } finally {
1502  1 selectTopFrame();
1503    }
1504   
1505    // Place the caret at the start of the third macro.
1506  1 moveCaret(getMacroOutputLocator(2) + ".firstChild.firstChild", 0);
1507  1 typeText("3");
1508   
1509    // Place the caret at the end of the third macro.
1510  1 moveCaret(getMacroOutputLocator(2) + ".firstChild.firstChild", 5);
1511  1 typeEnter();
1512  1 try {
1513  1 waitForDialogToLoad();
1514  0 fail("The macro edit box shouldn't be triggered by pressing Enter at the end of the output.");
1515    } catch (TimeoutException e) {
1516    // Expected.
1517    }
1518  1 typeText("2");
1519   
1520    // Place the caret at the start of the last macro.
1521  1 moveCaret(getMacroOutputLocator(4) + ".firstChild.firstChild", 0);
1522  1 typeEnter();
1523  1 typeText("4");
1524   
1525    // Place the caret at the end of the last macro.
1526  1 moveCaret(getMacroOutputLocator(4) + ".firstChild.firstChild", 4);
1527  1 typeEnter();
1528  1 typeText("5");
1529   
1530  1 switchToSource();
1531  1 assertSourceText("1{{info}}one{{/info}} {{warning}}two{{/warning}}3{{error}}three{{/error}}\n\n2"
1532    + "\n\n{{info}}\nfour\n{{/info}}\n\n4\n\n{{warning}}\nfive\n{{/warning}}\n\n5");
1533    }
1534   
1535    /**
1536    * @see XWIKI-7743: Wrong editor width when returning from full screen edit after editing/adding a macro
1537    */
 
1538  1 toggle @Test
1539    public void testEditorWidthIsRestoredAfterFullScreenEdit()
1540    {
1541  1 clickEditInFullScreen();
1542  1 refreshMacros();
1543  1 clickExitFullScreen();
1544    // The width of the rich text area should be reset after exiting the full screen edit.
1545  1 assertEquals("", getSelenium().getEval("window.document.getElementsByTagName('iframe')[0].style.width"));
1546    }
1547   
1548    /**
1549    * @param index the index of a macro inside the edited document
1550    * @return a {@link String} representing a DOM locator for the specified macro
1551    */
 
1552  24 toggle public String getMacroLocator(int index)
1553    {
1554  24 return "document.getElementsByClassName('macro')[" + index + "]";
1555    }
1556   
1557    /**
1558    * @return the number of macros detected in the edited document
1559    */
 
1560  1 toggle public long getMacroCount()
1561    {
1562  1 return (Long) getRichTextArea().executeScript("return document.getElementsByClassName('macro').length");
1563    }
1564   
1565    /**
1566    * @return the number of selected macros in the edited document
1567    */
 
1568  7 toggle public long getSelectedMacroCount()
1569    {
1570  7 return (Long) getRichTextArea()
1571    .executeScript("return document.getElementsByClassName('macro-selected').length");
1572    }
1573   
1574    /**
1575    * Wait for the specified number of macros to be selected.
1576    *
1577    * @param count the number of selected macros to wait for
1578    */
 
1579  4 toggle public void waitForSelectedMacroCount(final int count)
1580    {
1581  4 new Wait()
1582    {
 
1583  7 toggle public boolean until()
1584    {
1585  7 return count == getSelectedMacroCount();
1586    }
1587    }.wait("The specified number of selected macros, " + count + ", hasn't been reached in a decent amount of time");
1588    }
1589   
1590    /**
1591    * The macro place holder is shown when the macro is collapsed. In this state the output of the macro is hidden.
1592    *
1593    * @param index the index of a macro inside the edited document
1594    * @return a {@link String} representing a DOM locator for the place holder of the specified macro, relative to the
1595    * edited document
1596    */
 
1597  7 toggle public String getMacroPlaceHolderLocator(int index)
1598    {
1599  7 return "document.getElementsByClassName('macro-placeholder')[" + index + "]";
1600    }
1601   
1602    /**
1603    * The output of a macro is shown when the macro is expanded. In this state the macro place holder is hidden.
1604    *
1605    * @param index the index of a macro inside the edited document
1606    * @return a {@link String} representing a DOM locator for the output of the specified macro, relative to the edited
1607    * document
1608    */
 
1609  13 toggle public String getMacroOutputLocator(int index)
1610    {
1611  13 return "document.getElementsByClassName('macro-output')[" + index + "]";
1612    }
1613   
1614    /**
1615    * Selects the macro with the specified index in the edited document.
1616    *
1617    * @param index the index of the macro to be selected
1618    */
 
1619  21 toggle public void selectMacro(int index)
1620    {
1621  21 String locator = getMacroLocator(index);
1622  21 selectRichTextAreaFrame();
1623  21 try {
1624  21 getSelenium().mouseOver(locator);
1625  21 getSelenium().mouseMove(locator);
1626  21 getSelenium().mouseDown(locator);
1627  21 getSelenium().mouseUp(locator);
1628  21 getSelenium().click(locator);
1629  21 getSelenium().mouseMove(locator);
1630  21 getSelenium().mouseOut(locator);
1631    } finally {
1632  21 selectTopFrame();
1633    }
1634    // Select the macro container to be sure that the shortcut keys (Enter, Space) work. The click usually places
1635    // the caret at the start of the macro content when typing is allowed.
1636  21 selectNodeContents(locator);
1637    }
1638   
1639    /**
1640    * Collapses the currently selected macro or, if none is selected, all the macros using the shortcut key.
1641    */
 
1642  1 toggle public void collapseMacrosUsingShortcutKey()
1643    {
1644  1 getRichTextArea().sendKeys(Keys.chord(Keys.CONTROL, Keys.SHIFT, "c"));
1645    }
1646   
1647    /**
1648    * Expands the currently selected macro or, if none is selected, all the macros using the shortcut key.
1649    */
 
1650  0 toggle public void expandMacrosUsingShortcutKey()
1651    {
1652  0 getRichTextArea().sendKeys(Keys.chord(Keys.CONTROL, Keys.SHIFT, "e"));
1653    }
1654   
1655    /**
1656    * Toggles the collapsed state of the currently selected macro.
1657    */
 
1658  5 toggle public void toggleMacroCollapsedState()
1659    {
1660  5 getRichTextArea().sendKeys(Keys.SPACE);
1661    }
1662   
1663    /**
1664    * Opens the edit macro dialog to edit the specified macro.
1665    *
1666    * @param index the index of the macro to be edited
1667    */
 
1668  13 toggle public void editMacro(int index)
1669    {
1670  13 selectMacro(index);
1671  13 clickMenu(MENU_MACRO);
1672  13 clickMenu(MENU_EDIT);
1673  13 waitForDialogToLoad();
1674    }
1675   
1676    /**
1677    * Deletes the specified macro by selecting it and then pressing the Delete key.
1678    *
1679    * @param index the index of the macro to be deleted
1680    */
 
1681  1 toggle public void deleteMacro(int index)
1682    {
1683  1 selectMacro(index);
1684  1 typeDelete();
1685    }
1686   
1687    /**
1688    * Opens the insert macro dialog, chooses the specified macro and then opens the edit macro dialog to fill the
1689    * parameters of the selected macro.
1690    *
1691    * @param macroName the name of the macro to insert
1692    */
 
1693  7 toggle public void insertMacro(String macroName)
1694    {
1695  7 openSelectMacroDialog();
1696   
1697    // We have to wait for the specified macro to be displayed on the dialog because the loading indicator is
1698    // removed just before the list of macros is displayed and the Selenium click command can interfere.
1699  7 waitForMacroListItem(macroName, true);
1700  7 getSelenium().click(getMacroListItemLocator(macroName));
1701  7 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Select']");
1702  7 waitForDialogToLoad();
1703    }
1704   
1705    /**
1706    * Applies the changes from the edit macro dialog.<br/>
1707    * NOTE: This method can be called after both edit and insert macro actions.
1708    */
 
1709  28 toggle public void applyMacroChanges()
1710    {
1711    // The label of the finish button is "Apply" when we edit a macro and "Insert Macro" when we insert a macro.
1712  28 getSelenium().click("//div[@class = 'xDialogFooter']/button[text() = 'Apply' or text() = 'Insert Macro']");
1713  28 waitForEditorToLoad();
1714    }
1715   
1716    /**
1717    * Refreshes the macros present in the edited document using the menu.
1718    */
 
1719  6 toggle public void refreshMacros()
1720    {
1721  6 clickMenu(MENU_MACRO);
1722  6 clickMenu(MENU_REFRESH);
1723  6 waitForEditorToLoad();
1724    }
1725   
1726    /**
1727    * Refreshes the macros present in the edited document using the shortcut key.
1728    */
 
1729  2 toggle public void refreshMacrosUsingShortcutKey()
1730    {
1731  2 getRichTextArea().sendKeys(Keys.chord(Keys.CONTROL, Keys.SHIFT, "r"));
1732  2 waitForEditorToLoad();
1733    }
1734   
1735    /**
1736    * Selects the specified macro category.
1737    * <p>
1738    * NOTE: This method doesn't wait for the category to be loaded!
1739    *
1740    * @param category the name of the macro category to select
1741    */
 
1742  10 toggle public void selectMacroCategory(String category)
1743    {
1744  10 getSelenium().select(MACRO_CATEGORY_SELECTOR, category);
1745    }
1746   
1747    /**
1748    * @return the selected macro category
1749    */
 
1750  3 toggle public String getSelectedMacroCategory()
1751    {
1752  3 return getSelenium().getSelectedLabel(MACRO_CATEGORY_SELECTOR);
1753    }
1754   
1755    /**
1756    * Waits for the specified macro to be displayed or hidden on the "Select Macro" dialog.
1757    *
1758    * @param macroName the name of a macro
1759    * @param present {@code true} to wait for the specified macro to be present, {@code false} to wait for it to be
1760    * hidden
1761    */
 
1762  31 toggle public void waitForMacroListItem(final String macroName, final boolean present)
1763    {
1764  31 getDriver().waitUntilCondition(new ExpectedCondition<Boolean>()
1765    {
 
1766  52 toggle @Override
1767    public Boolean apply(WebDriver input)
1768    {
1769  52 return present == MacroTest.this.getDriver().hasElementWithoutWaiting(
1770    By.xpath(getMacroListItemLocator(macroName)));
1771    }
1772    });
1773    }
1774   
1775    /**
1776    * Waits for the specified number of macros to be listed on the "Select Macro" dialog.
1777    *
1778    * @param count the expected number of macros currently displayed on the "Select Macro" dialog
1779    */
 
1780  3 toggle public void waitForMacroListItemCount(final int count)
1781    {
1782  3 new Wait()
1783    {
 
1784  5 toggle public boolean until()
1785    {
1786  5 return count == getMacroListItemCount();
1787    }
1788    }.wait("The number of listed macros doesn't match.");
1789    }
1790   
1791    /**
1792    * @param macroName a macro name
1793    * @return the selector for the specified macro in the list of macros from the "Select Macro" dialog
1794    */
 
1795  70 toggle public String getMacroListItemLocator(String macroName)
1796    {
1797  70 return "//div[contains(@class, 'xListBox')]//div[contains(@class, 'xMacroLabel') and text() = '" + macroName
1798    + "']";
1799    }
1800   
1801    /**
1802    * @return the number of macro list items on the "Select Macro" dialog.
1803    */
 
1804  9 toggle public int getMacroListItemCount()
1805    {
1806  9 return getSelenium().getXpathCount("//div[contains(@class, 'xListItem xMacro')]").intValue();
1807    }
1808   
1809    /**
1810    * @param filter a text used to filter the macro list items
1811    * @return the number of macro list items containing the specified text
1812    */
 
1813  3 toggle public int getMacroListItemCount(String filter)
1814    {
1815  3 return getSelenium().getXpathCount(
1816    "//div[contains(@class, 'xListItem xMacro') and contains(., '" + filter + "')]").intValue();
1817    }
1818   
1819    /**
1820    * Sets the value of the live filter to the given string.
1821    *
1822    * @param filter the value to set to the live macro filter
1823    */
 
1824  3 toggle public void filterMacrosContaining(String filter)
1825    {
1826  3 getSelenium().typeKeys(MACRO_LIVE_FILTER_SELECTOR, filter);
1827    }
1828   
1829    /**
1830    * @return the value of the live macro filter
1831    */
 
1832  2 toggle public String getMacroFilterValue()
1833    {
1834  2 return getSelenium().getValue(MACRO_LIVE_FILTER_SELECTOR);
1835    }
1836   
1837    /**
1838    * Opens the "Select Macro" dialog.
1839    */
 
1840  18 toggle public void openSelectMacroDialog()
1841    {
1842  18 clickMenu(MENU_MACRO);
1843  18 assertTrue(isMenuEnabled(MENU_INSERT));
1844  18 clickMenu(MENU_INSERT);
1845  18 waitForDialogToLoad();
1846    }
1847   
1848    /**
1849    * @return {@code true} if there is a macro list item selected in the list of macros from the "Select Macro" dialog,
1850    * {@code false} otherwise
1851    */
 
1852  4 toggle public boolean isMacroListItemSelected()
1853    {
1854  4 return isElementPresent("//div[contains(@class, 'xMacro') and contains(@class, 'xListItem-selected')]");
1855    }
1856   
1857    /**
1858    * Clears the macro selection. No macro should be selected after calling this method.
1859    */
 
1860  2 toggle public void clearMacroSelection()
1861    {
1862  2 moveCaret("document.body", 0);
1863  2 triggerToolbarUpdate();
1864  2 waitForSelectedMacroCount(0);
1865    }
1866   
1867    /**
1868    * Clicks the tool bar button corresponding to the specified macro.
1869    *
1870    * @param macroId a macro identifier
1871    */
 
1872  1 toggle public void clickInsertMacroButton(String macroId)
1873    {
1874  1 pushToolBarButton(String.format("Insert %s macro", macroId));
1875    }
1876    }