|
1 var lastElement; |
|
2 |
|
3 function openContextMenuFor(element, shiftkey, waitForSpellCheck) { |
|
4 // Context menu should be closed before we open it again. |
|
5 is(SpecialPowers.wrap(contextMenu).state, "closed", "checking if popup is closed"); |
|
6 |
|
7 if (lastElement) |
|
8 lastElement.blur(); |
|
9 element.focus(); |
|
10 |
|
11 // Some elements need time to focus and spellcheck before any tests are |
|
12 // run on them. |
|
13 function actuallyOpenContextMenuFor() { |
|
14 lastElement = element; |
|
15 var eventDetails = { type : "contextmenu", button : 2, shiftKey : shiftkey }; |
|
16 synthesizeMouse(element, 2, 2, eventDetails, element.ownerDocument.defaultView); |
|
17 } |
|
18 |
|
19 if (waitForSpellCheck) |
|
20 onSpellCheck(element, actuallyOpenContextMenuFor); |
|
21 else |
|
22 actuallyOpenContextMenuFor(); |
|
23 } |
|
24 |
|
25 function closeContextMenu() { |
|
26 contextMenu.hidePopup(); |
|
27 } |
|
28 |
|
29 function getVisibleMenuItems(aMenu, aData) { |
|
30 var items = []; |
|
31 var accessKeys = {}; |
|
32 for (var i = 0; i < aMenu.childNodes.length; i++) { |
|
33 var item = aMenu.childNodes[i]; |
|
34 if (item.hidden) |
|
35 continue; |
|
36 |
|
37 var key = item.accessKey; |
|
38 if (key) |
|
39 key = key.toLowerCase(); |
|
40 |
|
41 var isGenerated = item.hasAttribute("generateditemid"); |
|
42 |
|
43 if (item.nodeName == "menuitem") { |
|
44 var isSpellSuggestion = item.className == "spell-suggestion"; |
|
45 if (isSpellSuggestion) { |
|
46 is(item.id, "", "child menuitem #" + i + " is a spelling suggestion"); |
|
47 } else if (isGenerated) { |
|
48 is(item.id, "", "child menuitem #" + i + " is a generated item"); |
|
49 } else { |
|
50 ok(item.id, "child menuitem #" + i + " has an ID"); |
|
51 } |
|
52 var label = item.getAttribute("label"); |
|
53 ok(label.length, "menuitem " + item.id + " has a label"); |
|
54 if (isSpellSuggestion) { |
|
55 is(key, "", "Spell suggestions shouldn't have an access key"); |
|
56 items.push("*" + label); |
|
57 } else if (isGenerated) { |
|
58 items.push("+" + label); |
|
59 } else if (item.id.indexOf("spell-check-dictionary-") != 0 && |
|
60 item.id != "spell-no-suggestions" && |
|
61 item.id != "spell-add-dictionaries-main") { |
|
62 ok(key, "menuitem " + item.id + " has an access key"); |
|
63 if (accessKeys[key]) |
|
64 ok(false, "menuitem " + item.id + " has same accesskey as " + accessKeys[key]); |
|
65 else |
|
66 accessKeys[key] = item.id; |
|
67 } |
|
68 if (!isSpellSuggestion && !isGenerated) { |
|
69 items.push(item.id); |
|
70 } |
|
71 if (isGenerated) { |
|
72 var p = {}; |
|
73 p.type = item.getAttribute("type"); |
|
74 p.icon = item.getAttribute("image"); |
|
75 p.checked = item.hasAttribute("checked"); |
|
76 p.disabled = item.hasAttribute("disabled"); |
|
77 items.push(p); |
|
78 } else { |
|
79 items.push(!item.disabled); |
|
80 } |
|
81 } else if (item.nodeName == "menuseparator") { |
|
82 ok(true, "--- seperator id is " + item.id); |
|
83 items.push("---"); |
|
84 items.push(null); |
|
85 } else if (item.nodeName == "menu") { |
|
86 if (isGenerated) { |
|
87 item.id = "generated-submenu-" + aData.generatedSubmenuId++; |
|
88 } |
|
89 ok(item.id, "child menu #" + i + " has an ID"); |
|
90 if (!isGenerated) { |
|
91 ok(key, "menu has an access key"); |
|
92 if (accessKeys[key]) |
|
93 ok(false, "menu " + item.id + " has same accesskey as " + accessKeys[key]); |
|
94 else |
|
95 accessKeys[key] = item.id; |
|
96 } |
|
97 items.push(item.id); |
|
98 items.push(!item.disabled); |
|
99 // Add a dummy item to that the indexes in checkMenu are the same |
|
100 // for expectedItems and actualItems. |
|
101 items.push([]); |
|
102 items.push(null); |
|
103 } else { |
|
104 ok(false, "child #" + i + " of menu ID " + aMenu.id + |
|
105 " has an unknown type (" + item.nodeName + ")"); |
|
106 } |
|
107 } |
|
108 return items; |
|
109 } |
|
110 |
|
111 function checkContextMenu(expectedItems) { |
|
112 is(contextMenu.state, "open", "checking if popup is open"); |
|
113 var data = { generatedSubmenuId: 1 }; |
|
114 checkMenu(contextMenu, expectedItems, data); |
|
115 } |
|
116 |
|
117 /* |
|
118 * checkMenu - checks to see if the specified <menupopup> contains the |
|
119 * expected items and state. |
|
120 * expectedItems is a array of (1) item IDs and (2) a boolean specifying if |
|
121 * the item is enabled or not (or null to ignore it). Submenus can be checked |
|
122 * by providing a nested array entry after the expected <menu> ID. |
|
123 * For example: ["blah", true, // item enabled |
|
124 * "submenu", null, // submenu |
|
125 * ["sub1", true, // submenu contents |
|
126 * "sub2", false], null, // submenu contents |
|
127 * "lol", false] // item disabled |
|
128 * |
|
129 */ |
|
130 function checkMenu(menu, expectedItems, data) { |
|
131 var actualItems = getVisibleMenuItems(menu, data); |
|
132 //ok(false, "Items are: " + actualItems); |
|
133 for (var i = 0; i < expectedItems.length; i+=2) { |
|
134 var actualItem = actualItems[i]; |
|
135 var actualEnabled = actualItems[i + 1]; |
|
136 var expectedItem = expectedItems[i]; |
|
137 var expectedEnabled = expectedItems[i + 1]; |
|
138 if (expectedItem instanceof Array) { |
|
139 ok(true, "Checking submenu..."); |
|
140 var menuID = expectedItems[i - 2]; // The last item was the menu ID. |
|
141 var submenu = menu.getElementsByAttribute("id", menuID)[0]; |
|
142 ok(submenu, "got a submenu element of id='" + menuID + "'"); |
|
143 if (submenu) { |
|
144 is(submenu.nodeName, "menu", "submenu element of id='" + menuID + |
|
145 "' has expected nodeName"); |
|
146 checkMenu(submenu.menupopup, expectedItem, data); |
|
147 } |
|
148 } else { |
|
149 is(actualItem, expectedItem, |
|
150 "checking item #" + i/2 + " (" + expectedItem + ") name"); |
|
151 |
|
152 if (typeof expectedEnabled == "object" && expectedEnabled != null || |
|
153 typeof actualEnabled == "object" && actualEnabled != null) { |
|
154 |
|
155 ok(!(actualEnabled == null), "actualEnabled is not null"); |
|
156 ok(!(expectedEnabled == null), "expectedEnabled is not null"); |
|
157 is(typeof actualEnabled, typeof expectedEnabled, "checking types"); |
|
158 |
|
159 if (typeof actualEnabled != typeof expectedEnabled || |
|
160 actualEnabled == null || expectedEnabled == null) |
|
161 continue; |
|
162 |
|
163 is(actualEnabled.type, expectedEnabled.type, |
|
164 "checking item #" + i/2 + " (" + expectedItem + ") type attr value"); |
|
165 var icon = actualEnabled.icon; |
|
166 if (icon) { |
|
167 var tmp = ""; |
|
168 var j = icon.length - 1; |
|
169 while (j && icon[j] != "/") { |
|
170 tmp = icon[j--] + tmp; |
|
171 } |
|
172 icon = tmp; |
|
173 } |
|
174 is(icon, expectedEnabled.icon, |
|
175 "checking item #" + i/2 + " (" + expectedItem + ") icon attr value"); |
|
176 is(actualEnabled.checked, expectedEnabled.checked, |
|
177 "checking item #" + i/2 + " (" + expectedItem + ") has checked attr"); |
|
178 is(actualEnabled.disabled, expectedEnabled.disabled, |
|
179 "checking item #" + i/2 + " (" + expectedItem + ") has disabled attr"); |
|
180 } else if (expectedEnabled != null) |
|
181 is(actualEnabled, expectedEnabled, |
|
182 "checking item #" + i/2 + " (" + expectedItem + ") enabled state"); |
|
183 } |
|
184 } |
|
185 // Could find unexpected extra items at the end... |
|
186 is(actualItems.length, expectedItems.length, "checking expected number of menu entries"); |
|
187 } |