Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* |
michael@0 | 2 | * This script is used for menu and popup tests. Call startPopupTests to start |
michael@0 | 3 | * the tests, passing an array of tests as an argument. Each test is an object |
michael@0 | 4 | * with the following properties: |
michael@0 | 5 | * testname - name of the test |
michael@0 | 6 | * test - function to call to perform the test |
michael@0 | 7 | * events - a list of events that are expected to be fired in sequence |
michael@0 | 8 | * as a result of calling the 'test' function. This list should be |
michael@0 | 9 | * an array of strings of the form "eventtype targetid" where |
michael@0 | 10 | * 'eventtype' is the event type and 'targetid' is the id of |
michael@0 | 11 | * target of the event. This function will be passed two |
michael@0 | 12 | * arguments, the testname and the step argument. |
michael@0 | 13 | * Alternatively, events may be a function which returns the array |
michael@0 | 14 | * of events. This can be used when the events vary per platform. |
michael@0 | 15 | * result - function to call after all the events have fired to check |
michael@0 | 16 | * for additional results. May be null. This function will be |
michael@0 | 17 | * passed two arguments, the testname and the step argument. |
michael@0 | 18 | * steps - optional array of values. The test will be repeated for |
michael@0 | 19 | * each step, passing each successive value within the array to |
michael@0 | 20 | * the test and result functions |
michael@0 | 21 | * autohide - if set, should be set to the id of a popup to hide after |
michael@0 | 22 | * the test is complete. This is a convenience for some tests. |
michael@0 | 23 | * condition - an optional function which, if it returns false, causes the |
michael@0 | 24 | * test to be skipped. |
michael@0 | 25 | * end - used for debugging. Set to true to stop the tests after running |
michael@0 | 26 | * this one. |
michael@0 | 27 | */ |
michael@0 | 28 | |
michael@0 | 29 | const menuactiveAttribute = "_moz-menuactive"; |
michael@0 | 30 | |
michael@0 | 31 | var gPopupTests = null; |
michael@0 | 32 | var gTestIndex = -1; |
michael@0 | 33 | var gTestStepIndex = 0; |
michael@0 | 34 | var gTestEventIndex = 0; |
michael@0 | 35 | var gAutoHide = false; |
michael@0 | 36 | var gExpectedEventDetails = null; |
michael@0 | 37 | var gExpectedTriggerNode = null; |
michael@0 | 38 | var gWindowUtils; |
michael@0 | 39 | var gPopupWidth = -1, gPopupHeight = -1; |
michael@0 | 40 | |
michael@0 | 41 | function startPopupTests(tests) |
michael@0 | 42 | { |
michael@0 | 43 | document.addEventListener("popupshowing", eventOccurred, false); |
michael@0 | 44 | document.addEventListener("popupshown", eventOccurred, false); |
michael@0 | 45 | document.addEventListener("popuphiding", eventOccurred, false); |
michael@0 | 46 | document.addEventListener("popuphidden", eventOccurred, false); |
michael@0 | 47 | document.addEventListener("command", eventOccurred, false); |
michael@0 | 48 | document.addEventListener("DOMMenuItemActive", eventOccurred, false); |
michael@0 | 49 | document.addEventListener("DOMMenuItemInactive", eventOccurred, false); |
michael@0 | 50 | document.addEventListener("DOMMenuInactive", eventOccurred, false); |
michael@0 | 51 | document.addEventListener("DOMMenuBarActive", eventOccurred, false); |
michael@0 | 52 | document.addEventListener("DOMMenuBarInactive", eventOccurred, false); |
michael@0 | 53 | |
michael@0 | 54 | gPopupTests = tests; |
michael@0 | 55 | gWindowUtils = SpecialPowers.getDOMWindowUtils(window); |
michael@0 | 56 | |
michael@0 | 57 | goNext(); |
michael@0 | 58 | } |
michael@0 | 59 | |
michael@0 | 60 | function finish() |
michael@0 | 61 | { |
michael@0 | 62 | if (window.opener) { |
michael@0 | 63 | window.close(); |
michael@0 | 64 | window.opener.SimpleTest.finish(); |
michael@0 | 65 | return; |
michael@0 | 66 | } |
michael@0 | 67 | SimpleTest.finish(); |
michael@0 | 68 | return; |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | function ok(condition, message) { |
michael@0 | 72 | if (window.opener) |
michael@0 | 73 | window.opener.SimpleTest.ok(condition, message); |
michael@0 | 74 | else |
michael@0 | 75 | SimpleTest.ok(condition, message); |
michael@0 | 76 | } |
michael@0 | 77 | |
michael@0 | 78 | function is(left, right, message) { |
michael@0 | 79 | if (window.opener) |
michael@0 | 80 | window.opener.SimpleTest.is(left, right, message); |
michael@0 | 81 | else |
michael@0 | 82 | SimpleTest.is(left, right, message); |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | function disableNonTestMouse(aDisable) { |
michael@0 | 86 | gWindowUtils.disableNonTestMouseEvents(aDisable); |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | function eventOccurred(event) |
michael@0 | 90 | { |
michael@0 | 91 | if (gPopupTests.length <= gTestIndex) { |
michael@0 | 92 | ok(false, "Extra " + event.type + " event fired"); |
michael@0 | 93 | return; |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | var test = gPopupTests[gTestIndex]; |
michael@0 | 97 | if ("autohide" in test && gAutoHide) { |
michael@0 | 98 | if (event.type == "DOMMenuInactive") { |
michael@0 | 99 | gAutoHide = false; |
michael@0 | 100 | setTimeout(goNextStep, 0); |
michael@0 | 101 | } |
michael@0 | 102 | return; |
michael@0 | 103 | } |
michael@0 | 104 | |
michael@0 | 105 | var events = test.events; |
michael@0 | 106 | if (typeof events == "function") |
michael@0 | 107 | events = events(); |
michael@0 | 108 | if (events) { |
michael@0 | 109 | if (events.length <= gTestEventIndex) { |
michael@0 | 110 | ok(false, "Extra " + event.type + " event fired for " + event.target.id + |
michael@0 | 111 | " " +gPopupTests[gTestIndex].testname); |
michael@0 | 112 | return; |
michael@0 | 113 | } |
michael@0 | 114 | |
michael@0 | 115 | var eventitem = events[gTestEventIndex].split(" "); |
michael@0 | 116 | var matches; |
michael@0 | 117 | if (eventitem[1] == "#tooltip") { |
michael@0 | 118 | is(event.originalTarget.localName, "tooltip", |
michael@0 | 119 | test.testname + " event.originalTarget.localName is 'tooltip'"); |
michael@0 | 120 | is(event.originalTarget.getAttribute("default"), "true", |
michael@0 | 121 | test.testname + " event.originalTarget default attribute is 'true'"); |
michael@0 | 122 | matches = event.originalTarget.localName == "tooltip" && |
michael@0 | 123 | event.originalTarget.getAttribute("default") == "true"; |
michael@0 | 124 | } else { |
michael@0 | 125 | is(event.type, eventitem[0], |
michael@0 | 126 | test.testname + " event type " + event.type + " fired"); |
michael@0 | 127 | is(event.target.id, eventitem[1], |
michael@0 | 128 | test.testname + " event target ID " + event.target.id); |
michael@0 | 129 | matches = eventitem[0] == event.type && eventitem[1] == event.target.id; |
michael@0 | 130 | } |
michael@0 | 131 | |
michael@0 | 132 | var modifiersMask = eventitem[2]; |
michael@0 | 133 | if (modifiersMask) { |
michael@0 | 134 | var m = ""; |
michael@0 | 135 | m += event.altKey ? '1' : '0'; |
michael@0 | 136 | m += event.ctrlKey ? '1' : '0'; |
michael@0 | 137 | m += event.shiftKey ? '1' : '0'; |
michael@0 | 138 | m += event.metaKey ? '1' : '0'; |
michael@0 | 139 | is(m, modifiersMask, test.testname + " modifiers mask matches"); |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | var expectedState; |
michael@0 | 143 | switch (event.type) { |
michael@0 | 144 | case "popupshowing": expectedState = "showing"; break; |
michael@0 | 145 | case "popupshown": expectedState = "open"; break; |
michael@0 | 146 | case "popuphiding": expectedState = "hiding"; break; |
michael@0 | 147 | case "popuphidden": expectedState = "closed"; break; |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | if (gExpectedTriggerNode && event.type == "popupshowing") { |
michael@0 | 151 | if (gExpectedTriggerNode == "notset") // check against null instead |
michael@0 | 152 | gExpectedTriggerNode = null; |
michael@0 | 153 | |
michael@0 | 154 | is(event.originalTarget.triggerNode, gExpectedTriggerNode, test.testname + " popupshowing triggerNode"); |
michael@0 | 155 | var isTooltip = (event.target.localName == "tooltip"); |
michael@0 | 156 | is(document.popupNode, isTooltip ? null : gExpectedTriggerNode, |
michael@0 | 157 | test.testname + " popupshowing document.popupNode"); |
michael@0 | 158 | is(document.tooltipNode, isTooltip ? gExpectedTriggerNode : null, |
michael@0 | 159 | test.testname + " popupshowing document.tooltipNode"); |
michael@0 | 160 | } |
michael@0 | 161 | |
michael@0 | 162 | if (expectedState) |
michael@0 | 163 | is(event.originalTarget.state, expectedState, |
michael@0 | 164 | test.testname + " " + event.type + " state"); |
michael@0 | 165 | |
michael@0 | 166 | if (matches) { |
michael@0 | 167 | gTestEventIndex++ |
michael@0 | 168 | if (events.length <= gTestEventIndex) |
michael@0 | 169 | setTimeout(checkResult, 0); |
michael@0 | 170 | } |
michael@0 | 171 | } |
michael@0 | 172 | } |
michael@0 | 173 | |
michael@0 | 174 | function checkResult() |
michael@0 | 175 | { |
michael@0 | 176 | var step = null; |
michael@0 | 177 | var test = gPopupTests[gTestIndex]; |
michael@0 | 178 | if ("steps" in test) |
michael@0 | 179 | step = test.steps[gTestStepIndex]; |
michael@0 | 180 | |
michael@0 | 181 | if ("result" in test) |
michael@0 | 182 | test.result(test.testname, step); |
michael@0 | 183 | |
michael@0 | 184 | if ("autohide" in test) { |
michael@0 | 185 | gAutoHide = true; |
michael@0 | 186 | document.getElementById(test.autohide).hidePopup(); |
michael@0 | 187 | return; |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | goNextStep(); |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | function goNextStep() |
michael@0 | 194 | { |
michael@0 | 195 | gTestEventIndex = 0; |
michael@0 | 196 | |
michael@0 | 197 | var step = null; |
michael@0 | 198 | var test = gPopupTests[gTestIndex]; |
michael@0 | 199 | if ("steps" in test) { |
michael@0 | 200 | gTestStepIndex++; |
michael@0 | 201 | step = test.steps[gTestStepIndex]; |
michael@0 | 202 | if (gTestStepIndex < test.steps.length) { |
michael@0 | 203 | test.test(test.testname, step); |
michael@0 | 204 | return; |
michael@0 | 205 | } |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | goNext(); |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | function goNext() |
michael@0 | 212 | { |
michael@0 | 213 | // We want to continue after the next animation frame so that |
michael@0 | 214 | // we're in a stable state and don't get spurious mouse events at unexpected targets. |
michael@0 | 215 | window.requestAnimationFrame( |
michael@0 | 216 | function() { |
michael@0 | 217 | setTimeout(goNextStepSync, 0); |
michael@0 | 218 | } |
michael@0 | 219 | ); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | function goNextStepSync() |
michael@0 | 223 | { |
michael@0 | 224 | if (gTestIndex >= 0 && "end" in gPopupTests[gTestIndex] && gPopupTests[gTestIndex].end) { |
michael@0 | 225 | finish(); |
michael@0 | 226 | return; |
michael@0 | 227 | } |
michael@0 | 228 | |
michael@0 | 229 | gTestIndex++; |
michael@0 | 230 | gTestStepIndex = 0; |
michael@0 | 231 | if (gTestIndex < gPopupTests.length) { |
michael@0 | 232 | var test = gPopupTests[gTestIndex]; |
michael@0 | 233 | // Set the location hash so it's easy to see which test is running |
michael@0 | 234 | document.location.hash = test.testname; |
michael@0 | 235 | |
michael@0 | 236 | // skip the test if the condition returns false |
michael@0 | 237 | if ("condition" in test && !test.condition()) { |
michael@0 | 238 | goNext(); |
michael@0 | 239 | return; |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | // start with the first step if there are any |
michael@0 | 243 | var step = null; |
michael@0 | 244 | if ("steps" in test) |
michael@0 | 245 | step = test.steps[gTestStepIndex]; |
michael@0 | 246 | |
michael@0 | 247 | test.test(test.testname, step); |
michael@0 | 248 | |
michael@0 | 249 | // no events to check for so just check the result |
michael@0 | 250 | if (!("events" in test)) |
michael@0 | 251 | checkResult(); |
michael@0 | 252 | } |
michael@0 | 253 | else { |
michael@0 | 254 | finish(); |
michael@0 | 255 | } |
michael@0 | 256 | } |
michael@0 | 257 | |
michael@0 | 258 | function openMenu(menu) |
michael@0 | 259 | { |
michael@0 | 260 | if ("open" in menu) { |
michael@0 | 261 | menu.open = true; |
michael@0 | 262 | } |
michael@0 | 263 | else { |
michael@0 | 264 | var bo = menu.boxObject; |
michael@0 | 265 | if (bo instanceof SpecialPowers.Ci.nsIMenuBoxObject) |
michael@0 | 266 | bo.openMenu(true); |
michael@0 | 267 | else |
michael@0 | 268 | synthesizeMouse(menu, 4, 4, { }); |
michael@0 | 269 | } |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | function closeMenu(menu, popup) |
michael@0 | 273 | { |
michael@0 | 274 | if ("open" in menu) { |
michael@0 | 275 | menu.open = false; |
michael@0 | 276 | } |
michael@0 | 277 | else { |
michael@0 | 278 | var bo = menu.boxObject; |
michael@0 | 279 | if (bo instanceof SpecialPowers.Ci.nsIMenuBoxObject) |
michael@0 | 280 | bo.openMenu(false); |
michael@0 | 281 | else |
michael@0 | 282 | popup.hidePopup(); |
michael@0 | 283 | } |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | function checkActive(popup, id, testname) |
michael@0 | 287 | { |
michael@0 | 288 | var activeok = true; |
michael@0 | 289 | var children = popup.childNodes; |
michael@0 | 290 | for (var c = 0; c < children.length; c++) { |
michael@0 | 291 | var child = children[c]; |
michael@0 | 292 | if ((id == child.id && child.getAttribute(menuactiveAttribute) != "true") || |
michael@0 | 293 | (id != child.id && child.hasAttribute(menuactiveAttribute) != "")) { |
michael@0 | 294 | activeok = false; |
michael@0 | 295 | break; |
michael@0 | 296 | } |
michael@0 | 297 | } |
michael@0 | 298 | ok(activeok, testname + " item " + (id ? id : "none") + " active"); |
michael@0 | 299 | } |
michael@0 | 300 | |
michael@0 | 301 | function checkOpen(menuid, testname) |
michael@0 | 302 | { |
michael@0 | 303 | var menu = document.getElementById(menuid); |
michael@0 | 304 | if ("open" in menu) |
michael@0 | 305 | ok(menu.open, testname + " " + menuid + " menu is open"); |
michael@0 | 306 | else if (menu.boxObject instanceof SpecialPowers.Ci.nsIMenuBoxObject) |
michael@0 | 307 | ok(menu.getAttribute("open") == "true", testname + " " + menuid + " menu is open"); |
michael@0 | 308 | } |
michael@0 | 309 | |
michael@0 | 310 | function checkClosed(menuid, testname) |
michael@0 | 311 | { |
michael@0 | 312 | var menu = document.getElementById(menuid); |
michael@0 | 313 | if ("open" in menu) |
michael@0 | 314 | ok(!menu.open, testname + " " + menuid + " menu is open"); |
michael@0 | 315 | else if (menu.boxObject instanceof SpecialPowers.Ci.nsIMenuBoxObject) |
michael@0 | 316 | ok(!menu.hasAttribute("open"), testname + " " + menuid + " menu is closed"); |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | function convertPosition(anchor, align) |
michael@0 | 320 | { |
michael@0 | 321 | if (anchor == "topleft" && align == "topleft") return "overlap"; |
michael@0 | 322 | if (anchor == "topleft" && align == "topright") return "start_before"; |
michael@0 | 323 | if (anchor == "topleft" && align == "bottomleft") return "before_start"; |
michael@0 | 324 | if (anchor == "topright" && align == "topleft") return "end_before"; |
michael@0 | 325 | if (anchor == "topright" && align == "bottomright") return "before_end"; |
michael@0 | 326 | if (anchor == "bottomleft" && align == "bottomright") return "start_after"; |
michael@0 | 327 | if (anchor == "bottomleft" && align == "topleft") return "after_start"; |
michael@0 | 328 | if (anchor == "bottomright" && align == "bottomleft") return "end_after"; |
michael@0 | 329 | if (anchor == "bottomright" && align == "topright") return "after_end"; |
michael@0 | 330 | return ""; |
michael@0 | 331 | } |
michael@0 | 332 | |
michael@0 | 333 | /* |
michael@0 | 334 | * When checking position of the bottom or right edge of the popup's rect, |
michael@0 | 335 | * use this instead of strict equality check of rounded values, |
michael@0 | 336 | * because we snap the top/left edges to pixel boundaries, |
michael@0 | 337 | * which can shift the bottom/right up to 0.5px from its "ideal" location, |
michael@0 | 338 | * and could cause it to round differently. (See bug 622507.) |
michael@0 | 339 | */ |
michael@0 | 340 | function isWithinHalfPixel(a, b) |
michael@0 | 341 | { |
michael@0 | 342 | return Math.abs(a - b) <= 0.5; |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | function compareEdge(anchor, popup, edge, offsetX, offsetY, testname) |
michael@0 | 346 | { |
michael@0 | 347 | testname += " " + edge; |
michael@0 | 348 | |
michael@0 | 349 | checkOpen(anchor.id, testname); |
michael@0 | 350 | |
michael@0 | 351 | var anchorrect = anchor.getBoundingClientRect(); |
michael@0 | 352 | var popuprect = popup.getBoundingClientRect(); |
michael@0 | 353 | var check1 = false, check2 = false; |
michael@0 | 354 | |
michael@0 | 355 | if (gPopupWidth == -1) { |
michael@0 | 356 | ok((Math.round(popuprect.right) - Math.round(popuprect.left)) && |
michael@0 | 357 | (Math.round(popuprect.bottom) - Math.round(popuprect.top)), |
michael@0 | 358 | testname + " size"); |
michael@0 | 359 | } |
michael@0 | 360 | else { |
michael@0 | 361 | is(Math.round(popuprect.width), gPopupWidth, testname + " width"); |
michael@0 | 362 | is(Math.round(popuprect.height), gPopupHeight, testname + " height"); |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | var spaceIdx = edge.indexOf(" "); |
michael@0 | 366 | if (spaceIdx > 0) { |
michael@0 | 367 | let cornerX, cornerY; |
michael@0 | 368 | let [anchor, align] = edge.split(" "); |
michael@0 | 369 | switch (anchor) { |
michael@0 | 370 | case "topleft": cornerX = anchorrect.left; cornerY = anchorrect.top; break; |
michael@0 | 371 | case "topcenter": cornerX = anchorrect.left + anchorrect.width / 2; cornerY = anchorrect.top; break; |
michael@0 | 372 | case "topright": cornerX = anchorrect.right; cornerY = anchorrect.top; break; |
michael@0 | 373 | case "leftcenter": cornerX = anchorrect.left; cornerY = anchorrect.top + anchorrect.height / 2; break; |
michael@0 | 374 | case "rightcenter": cornerX = anchorrect.right; cornerY = anchorrect.top + anchorrect.height / 2; break; |
michael@0 | 375 | case "bottomleft": cornerX = anchorrect.left; cornerY = anchorrect.bottom; break; |
michael@0 | 376 | case "bottomcenter": cornerX = anchorrect.left + anchorrect.width / 2; cornerY = anchorrect.bottom; break; |
michael@0 | 377 | case "bottomright": cornerX = anchorrect.right; cornerY = anchorrect.bottom; break; |
michael@0 | 378 | } |
michael@0 | 379 | |
michael@0 | 380 | switch (align) { |
michael@0 | 381 | case "topleft": cornerX += offsetX; cornerY += offsetY; break; |
michael@0 | 382 | case "topright": cornerX += -popuprect.width + offsetX; cornerY += offsetY; break; |
michael@0 | 383 | case "bottomleft": cornerX += offsetX; cornerY += -popuprect.height + offsetY; break; |
michael@0 | 384 | case "bottomright": cornerX += -popuprect.width + offsetX; cornerY += -popuprect.height + offsetY; break; |
michael@0 | 385 | } |
michael@0 | 386 | |
michael@0 | 387 | is(Math.round(popuprect.left), Math.round(cornerX), testname + " x position"); |
michael@0 | 388 | is(Math.round(popuprect.top), Math.round(cornerY), testname + " y position"); |
michael@0 | 389 | return; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | if (edge == "after_pointer") { |
michael@0 | 393 | is(Math.round(popuprect.left), Math.round(anchorrect.left) + offsetX, testname + " x position"); |
michael@0 | 394 | is(Math.round(popuprect.top), Math.round(anchorrect.top) + offsetY + 21, testname + " y position"); |
michael@0 | 395 | return; |
michael@0 | 396 | } |
michael@0 | 397 | |
michael@0 | 398 | if (edge == "overlap") { |
michael@0 | 399 | ok(Math.round(anchorrect.left) + offsetY == Math.round(popuprect.left) && |
michael@0 | 400 | Math.round(anchorrect.top) + offsetY == Math.round(popuprect.top), |
michael@0 | 401 | testname + " position"); |
michael@0 | 402 | return; |
michael@0 | 403 | } |
michael@0 | 404 | |
michael@0 | 405 | if (edge.indexOf("before") == 0) |
michael@0 | 406 | check1 = isWithinHalfPixel(anchorrect.top + offsetY, popuprect.bottom); |
michael@0 | 407 | else if (edge.indexOf("after") == 0) |
michael@0 | 408 | check1 = (Math.round(anchorrect.bottom) + offsetY == Math.round(popuprect.top)); |
michael@0 | 409 | else if (edge.indexOf("start") == 0) |
michael@0 | 410 | check1 = isWithinHalfPixel(anchorrect.left + offsetX, popuprect.right); |
michael@0 | 411 | else if (edge.indexOf("end") == 0) |
michael@0 | 412 | check1 = (Math.round(anchorrect.right) + offsetX == Math.round(popuprect.left)); |
michael@0 | 413 | |
michael@0 | 414 | if (0 < edge.indexOf("before")) |
michael@0 | 415 | check2 = (Math.round(anchorrect.top) + offsetY == Math.round(popuprect.top)); |
michael@0 | 416 | else if (0 < edge.indexOf("after")) |
michael@0 | 417 | check2 = isWithinHalfPixel(anchorrect.bottom + offsetY, popuprect.bottom); |
michael@0 | 418 | else if (0 < edge.indexOf("start")) |
michael@0 | 419 | check2 = (Math.round(anchorrect.left) + offsetX == Math.round(popuprect.left)); |
michael@0 | 420 | else if (0 < edge.indexOf("end")) |
michael@0 | 421 | check2 = isWithinHalfPixel(anchorrect.right + offsetX, popuprect.right); |
michael@0 | 422 | |
michael@0 | 423 | ok(check1 && check2, testname + " position"); |
michael@0 | 424 | } |