// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. //----------------------------------------------------------------------------- // Position Tests for the "anchor" element of the tooltip (absolute, fixed, relative, relative). // Make sure the tooltip still appears at the correct spot when the "anchor" element is positioned // using this CSS property. This also tests when the html/body/parent element are scrolled. // To verify this, let's just measure the distance from the tooltip to the anchor. //----------------------------------------------------------------------------- // // /// /// // module WinJSTests { 'use strict'; var tooltipUtils = TooltipUtils; var commonUtils = Helper; // Since distances can be off due to rounding errors, use this tolerance for our comparisons. var DISTANCE_TOLERANCE = 1; // Verify the tooltip appears at the specified distance from the element. function testTooltip_VerifyPosition(signalTestCaseCompleted, elementPosition, parentPosition, scrollThe, inputMethod) { LiveUnit.LoggingCore.logComment("When the anchor element is positioned: " + elementPosition); LiveUnit.LoggingCore.logComment("And we scroll the: " + scrollThe); LiveUnit.LoggingCore.logComment("And we use: " + inputMethod); LiveUnit.LoggingCore.logComment("Window size: " + window.innerWidth + " " + window.innerHeight); // Set up the anchor/trigger element. var element = document.getElementById(tooltipUtils.defaultElementID); var parentElement = document.getElementById("parentElement"); if (scrollThe === "html") { window.scrollTo(25, 25); } else { window.scrollTo(0, 0); } if (scrollThe === "body") { WinJS.Utilities.setScrollPosition(document.body, { scrollLeft: 25, scrollTop: 25 }); } else { WinJS.Utilities.setScrollPosition(document.body, { scrollLeft: 0, scrollTop: 0 }); } if (scrollThe === "parent") { parentElement.style.width = "100px"; parentElement.style.height = "100px"; parentElement.style.top = "100px"; parentElement.style.left = "100px"; parentElement.style.overflow = "scroll"; WinJS.Utilities.setScrollPosition(parentElement, { scrollLeft: 25, scrollTop: 25 }); } else { parentElement.style.width = ""; parentElement.style.height = ""; parentElement.style.top = ""; parentElement.style.left = ""; parentElement.style.overflow = "auto"; WinJS.Utilities.setScrollPosition(parentElement, { scrollLeft: 0, scrollTop: 0 }); } // Position the element parentElement.style.position = parentPosition; element.style.position = elementPosition; element.style.left = "100px"; element.style.top = "100px"; // set up the tooltip var tooltip = tooltipUtils.instantiate(tooltipUtils.defaultElementID, { innerHTML: "t" }); var testComplete = false; function tooltipEventListener(event) { if (testComplete) { return; } LiveUnit.Assert.isNotNull(event); LiveUnit.LoggingCore.logComment(event.type); tooltipUtils.logTooltipInformation(tooltip); switch (event.type) { case "trigger": tooltipUtils.displayTooltip(inputMethod, element, tooltip); break; case "opened": LiveUnit.Assert.isTrue(tooltipUtils.getTooltipDistanceFromWindow(tooltip) >= 0); var distance; // Let's just use these inputMethods (and not touch, keyboardProgrammatic, etc.) // They should cover all the main scenarios for positioning: basically the tooltip // is either positioned based on the touch/mouse point, or based on the element position. switch (inputMethod) { case "keyboard": distance = tooltipUtils.OFFSET_KEYBOARD; break; case "mouse": distance = tooltipUtils.OFFSET_MOUSE; break; case "mouseoverProgrammatic": distance = tooltipUtils.OFFSET_PROGRAMMATIC_NONTOUCH; break; default: LiveUnit.Assert.fail("Unknown inputMethod " + inputMethod); break; } var actualDistance = tooltipUtils.getTooltipDistanceFromElement(tooltip, (((inputMethod == "touch") || (inputMethod == "mouse")) ? "center" : "edge")); // On some browsers, the actual distance will be reported as 21.00000123 which will fail asserts which don't really matter actualDistance = Math.round(actualDistance); LiveUnit.Assert.isTrue((actualDistance <= (distance + DISTANCE_TOLERANCE)), "Expected distance: " + distance); LiveUnit.Assert.isTrue((actualDistance >= (distance - DISTANCE_TOLERANCE)), "Expected distance: " + distance); signalTestCaseCompleted(); testComplete = true; break; } } tooltipUtils.setupTooltipListener(tooltip, tooltipEventListener); } export class TooltipPositionTests { setUp() { // Add a sibling element before our element. This helps us test static positioning. commonUtils.addTag("div", "siblingBeforeElement"); var siblingBeforeElement = document.getElementById("siblingBeforeElement"); siblingBeforeElement.innerHTML = "siblingBeforeElement"; // Add a parent element. This helps us with scrolling the anchor element when inside a commonUtils.addTag("span", "parentElement"); var parentElement = document.getElementById("parentElement"); parentElement.style.backgroundColor = "Blue"; tooltipUtils.setUp(); // Move the anchor element beneath a so we can test scrolling the var span1 = document.createElement("span"); span1.innerHTML = "AAAAAAA BBBBBBB CCCCCCC DDDDDD"; parentElement.appendChild(span1); var element = document.getElementById(tooltipUtils.defaultElementID); commonUtils.removeElementById(tooltipUtils.defaultElementID); element.textContent = "e"; parentElement.appendChild(element); var span2 = document.createElement("span"); span2.innerHTML = "EEEEE FFFFFF GGGGGG HHHHHHH"; parentElement.appendChild(span2); // Make each child element progressively larger, to ensure they can scroll. document.documentElement.style.overflow = "scroll"; document.documentElement.style.width = (window.innerWidth + 200) + "px"; document.documentElement.style.height = (window.innerHeight + 200) + "px"; document.body.style.overflow = "scroll"; document.body.style.width = (window.innerWidth + 400) + "px"; document.body.style.height = (window.innerHeight + 400) + "px"; // Add a sibling element after our element. This helps us make our scrollable if needed. commonUtils.addTag("div", "siblingAfterElement"); var siblingAfterElement = document.getElementById("siblingAfterElement"); siblingAfterElement.innerHTML = "siblingAfterElement"; siblingAfterElement.style.backgroundColor = "Gray"; siblingAfterElement.style.width = (window.innerWidth + 600) + "px"; siblingAfterElement.style.height = (window.innerHeight + 600) + "px"; } tearDown() { var element = document.getElementById(tooltipUtils.defaultElementID); element.winControl.dispose(); commonUtils.removeElementById("siblingBeforeElement"); tooltipUtils.cleanUp(); commonUtils.removeElementById("parentElement"); commonUtils.removeElementById("siblingAfterElement"); } } Helper.pairwise({ elementPosition: ['absolute', 'fixed', 'relative', 'static'], parentPosition: ['static', 'absolute'], scrollThe: ['none', 'body', 'html', 'parent'], inputMethod: ['mouse', 'mouseoverProgrammatic', 'keyboard'] }).forEach(function (testCase) { var testNameParts = ["testTooltip_Position"]; testNameParts.push(testCase.elementPosition); testNameParts.push(testCase.parentPosition); if (testCase.scrollThe !== 'none') { testNameParts.push(testCase.scrollThe, "Scrolled"); } testNameParts.push(testCase.inputMethod); var testName = testNameParts.join(''); TooltipPositionTests.prototype[testName] = function (signalTestCaseCompleted) { testTooltip_VerifyPosition(signalTestCaseCompleted, testCase.elementPosition, testCase.parentPosition, testCase.scrollThe, testCase.inputMethod); } }); } // Saucelabs VMs hang on this test suite if (!Helper.Browser.isIE10) { // Register the object as a test class by passing in the name LiveUnit.registerTestClass("WinJSTests.TooltipPositionTests"); }