// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. // // /// declare var Windows; module AutoSuggestBoxTests { "use strict"; var Key = WinJS.Utilities.Key; var AutoSuggestBox = WinJS.UI.AutoSuggestBox; function waitForSuggestionFlyoutRender(asb) { return new WinJS.Promise(function (c) { function register() { asb._repeater.addEventListener("iteminserted", handle); asb._repeater.addEventListener("itemremoved", handle); } function unregister() { asb._repeater.removeEventListener("iteminserted", handle); asb._repeater.removeEventListener("itemremoved", handle); } function handle() { unregister(); WinJS.Promise.timeout().then(c); } register(); }); } // Util functions function createCustomEvent(type, details?) { var ev = document.createEvent("CustomEvent"); ev.initCustomEvent(type, true, true, details); return ev; } function mockInputContext(inputElement, compositionStartOffset, compositionEndOffset, alternatives) { //mock msGetInputContext so we can have more control over the events inputElement.msGetInputContext = function () { return { getCompositionAlternatives: function () { return alternatives; }, getCandidateWindowClientRect: function () { return { bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0 }; }, compositionEndOffset: compositionEndOffset, compositionStartOffset: compositionStartOffset } }; }; function verifyLinguisticDetails(linguisticDetails, expectedCompStart, expectedCompLength, expectedAlternatives) { LiveUnit.Assert.isNotNull(linguisticDetails); LiveUnit.Assert.isNotNull(linguisticDetails.queryTextCompositionStart); LiveUnit.Assert.areEqual(expectedCompStart, linguisticDetails.queryTextCompositionStart, "Unexpected composition string start."); LiveUnit.Assert.isNotNull(linguisticDetails.queryTextCompositionLength); LiveUnit.Assert.areEqual(expectedCompLength, linguisticDetails.queryTextCompositionLength, "Unexpected composition string length."); LiveUnit.Assert.isNotNull(linguisticDetails.queryTextAlternatives); LiveUnit.Assert.areEqual(expectedAlternatives.length, linguisticDetails.queryTextAlternatives.length, "Unexpected number of alternatives"); for (var i = 0; i < expectedAlternatives.length; i++) { LiveUnit.Assert.areEqual(expectedAlternatives[i], linguisticDetails.queryTextAlternatives[i], "Unexpected alternative value"); } }; export class AutoSuggestBoxTests { setUp() { // This is the setup function that will be called at the beginning of each test function. LiveUnit.LoggingCore.logComment("Attempt to Instantiate the ASB element"); var asbElement = document.createElement('div'); asbElement.id = "ASBID"; document.body.appendChild(asbElement); var asb: WinJS.UI.PrivateAutoSuggestBox = new AutoSuggestBox(asbElement, { searchHistoryDisabled: true }); LiveUnit.LoggingCore.logComment("ASB has been instantiated."); LiveUnit.Assert.isNotNull(asb, "ASB element should not be null when instantiated."); } tearDown() { LiveUnit.LoggingCore.logComment("In tearDown"); var element = document.getElementById("ASBID"); if (element) { WinJS.Utilities.disposeSubTree(element); document.body.removeChild(element); } } // Test functions testInitTest = function () { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; LiveUnit.LoggingCore.logComment("Verifying..."); // verify asb element LiveUnit.Assert.isNotNull(asb.element); // verify input element LiveUnit.Assert.isNotNull(asb._inputElement); // verify flyout LiveUnit.Assert.isNotNull(asb._flyoutElement); // verify repeater LiveUnit.Assert.isNotNull(asb._repeaterElement); }; testASBNullInstantiation = function () { // Test ASB Instantiation with null element LiveUnit.LoggingCore.logComment("Attempt to Instantiate the ASB with null element"); var asb = new AutoSuggestBox(null); LiveUnit.Assert.isNotNull(asb, "ASB instantiation was null when sent a null element."); } testASBMultipleInstantiation() { // Test multiple instantiation of the same ASB DOM element this.testASBMultipleInstantiation["LiveUnit.ExpectedException"] = { message: "Invalid argument: Controls may only be instantiated one time for each DOM element" }; // Get the ASB element from the DOM var asbElement = document.querySelector("#ASBID"); LiveUnit.LoggingCore.logComment("Attempt to Instantiate the ASB element again"); new AutoSuggestBox(asbElement); } testPublicApiSurfaceFunctions() { // This test only verifies the API surface. It does not test the functionality. var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; LiveUnit.LoggingCore.logComment("Waiting for control..."); LiveUnit.LoggingCore.logComment("Verifying..."); function verifyFunction(functionName) { LiveUnit.LoggingCore.logComment("Verifying that function " + functionName + " exists"); if (asb[functionName] === undefined) { LiveUnit.Assert.fail(functionName + " missing from ASB"); } LiveUnit.Assert.isNotNull(asb[functionName]); LiveUnit.Assert.areEqual("function", typeof (asb[functionName]), functionName + " exists on ASB, but it isn't a function"); } verifyFunction("addEventListener"); verifyFunction("removeEventListener"); verifyFunction("dispose"); verifyFunction("setLocalContentSuggestionSettings"); } testPublicApiSurfaceProperties() { // This test only verifies the API surface. It does not test the functionality. var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; LiveUnit.LoggingCore.logComment("Verifying..."); function verifyProperty(propertyName, propertyType) { LiveUnit.LoggingCore.logComment("Verifying that property " + propertyName + " exists"); if (asb[propertyName] === undefined) { LiveUnit.Assert.fail(propertyName + " missing from ASB"); } LiveUnit.Assert.isNotNull(asb[propertyName]); LiveUnit.Assert.areEqual(propertyType, typeof (asb[propertyName]), propertyName + " exists on ASB, but it isn't the right property type"); } verifyProperty("chooseSuggestionOnEnter", "boolean"); verifyProperty("searchHistoryContext", "string"); verifyProperty("searchHistoryDisabled", "boolean"); verifyProperty("queryText", "string"); verifyProperty("placeholderText", "string"); verifyProperty("disabled", "boolean"); } testASBDispose() { var asb: WinJS.UI.PrivateAutoSuggestBox = new AutoSuggestBox(); LiveUnit.Assert.isTrue(asb.dispose); LiveUnit.Assert.isFalse(asb._disposed); asb.dispose(); LiveUnit.Assert.isTrue(asb._disposed); asb.dispose(); } testASBDisposeSubTree() { var asbParent = document.createElement('div'); var asbElement = document.createElement('div'); var asb: WinJS.UI.PrivateAutoSuggestBox = new AutoSuggestBox(asbElement); asbParent.appendChild(asbElement); document.body.appendChild(asbParent); LiveUnit.Assert.isTrue(asb.dispose); LiveUnit.Assert.isFalse(asb._disposed); WinJS.Utilities.disposeSubTree(asbParent); LiveUnit.Assert.isTrue(asb._disposed); asb.dispose(); document.body.removeChild(asbParent); } testSimpleFunctions() { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; LiveUnit.LoggingCore.logComment("Verifying..."); var testPlaceHolder = "Test placeholder"; asb.placeholderText = testPlaceHolder; LiveUnit.Assert.areEqual(testPlaceHolder, asb.placeholderText, "Unable to set placeholderText"); var testQuery = "Test queryText"; asb.queryText = testQuery; LiveUnit.Assert.areEqual(testQuery, asb.queryText, "Unable to set queryText"); LiveUnit.Assert.areEqual(false, asb.chooseSuggestionOnEnter, "Incorrect default value for chooseSuggestionOnEnterDisabled"); var chooseSuggestionOnEnter = true; asb.chooseSuggestionOnEnter = chooseSuggestionOnEnter; LiveUnit.Assert.areEqual(chooseSuggestionOnEnter, asb.chooseSuggestionOnEnter, "Unable to set chooseSuggestionOnEnter"); LiveUnit.Assert.isFalse(asb.disabled, "Incorrect default value for disabled"); LiveUnit.Assert.isFalse(asb._inputElement.disabled, "Incorrect default value for disabled for input element."); asb.disabled = true; LiveUnit.Assert.isTrue(asb.disabled, "Unable to set disabled"); LiveUnit.Assert.isTrue(asb._inputElement.disabled, "ASB did not disable input element."); } testQueryChanged() { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; LiveUnit.LoggingCore.logComment("Verifying..."); var eventFired = false; asb.addEventListener("querychanged", function asbTest_queryChanged_listener(event) { LiveUnit.Assert.areEqual("Test query", event.detail.queryText, "Query text not matching input"); if (!window['Windows']) { //in web context, we match based on event details LiveUnit.Assert.areEqual("ja", event.detail.language, "Query text language not matching input"); } else { //in local context, we should match the WinRT API LiveUnit.Assert.areEqual(Windows.Globalization.Language.currentInputMethodLanguageTag, event.detail.language, "Query text language not matching input"); } LiveUnit.Assert.isFalse(eventFired, "Querychanged fired multiple times"); eventFired = true; }); // This is to test the input language Helper.keydown(asb._inputElement, Key.rightArrow, "ja"); LiveUnit.Assert.areEqual("ja", asb._lastKeyPressLanguage); asb._inputElement.value = "Test query"; asb._inputOrImeChangeHandler(null); LiveUnit.Assert.isTrue(eventFired, "QueryChanged event was not fired"); } testQuerySubmitted() { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; var eventFired = false; LiveUnit.LoggingCore.logComment("Verifying..."); asb.addEventListener("querysubmitted", function asbTest_queryChanged_listener(event) { LiveUnit.Assert.areEqual("Test query", event.detail.queryText, "Query text not matching input"); if (!window['Windows']) { //in web context, we match based on event details LiveUnit.Assert.areEqual("ja-JP", event.detail.language, "Query text language not matching input"); } else { //in local context, we should match the WinRT API LiveUnit.Assert.areEqual(Windows.Globalization.Language.currentInputMethodLanguageTag, event.detail.language, "Query text language not matching input"); } LiveUnit.Assert.isFalse(eventFired, "QuerySubmitted fired multiple times"); eventFired = true; }); // This is to test the input language Helper.keydown(asb._inputElement, Key.rightArrow, "ja"); LiveUnit.Assert.areEqual("ja", asb._lastKeyPressLanguage); asb._inputElement.value = "Test query"; Helper.keydown(asb._inputElement, Key.enter, "ja-JP"); LiveUnit.Assert.isTrue(eventFired, "QuerySubmitted event was not fired"); } testHitSortAndMerge() { var result; var testSingleHit = [{ startPosition: 2, length: 3 }]; result = AutoSuggestBox._sortAndMergeHits(testSingleHit); LiveUnit.Assert.areEqual(1, result.length, "testSingleHit: Did not receive correct number of results"); LiveUnit.Assert.areEqual(2, result[0].startPosition, "testSingleHit: Did not receive correct startPosition"); LiveUnit.Assert.areEqual(3, result[0].length, "testSingleHit: Did not receive correct length"); var testSort = [{ startPosition: 20, length: 4 }, { startPosition: 10, length: 3 }]; result = AutoSuggestBox._sortAndMergeHits(testSort); LiveUnit.Assert.areEqual(2, result.length, "testSort: Did not receive correct number of results"); LiveUnit.Assert.areEqual(10, result[0].startPosition, "testSort: Did not receive correct startPosition"); LiveUnit.Assert.areEqual(3, result[0].length, "testSort: Did not receive correct length"); LiveUnit.Assert.areEqual(20, result[1].startPosition, "testSort: Did not receive correct startPosition"); LiveUnit.Assert.areEqual(4, result[1].length, "testSort: Did not receive correct length"); var testMergeInside = [{ startPosition: 20, length: 1 }, { startPosition: 19, length: 3 }]; result = AutoSuggestBox._sortAndMergeHits(testMergeInside); LiveUnit.Assert.areEqual(1, result.length, "testMergeInside: Did not receive correct number of results"); LiveUnit.Assert.areEqual(19, result[0].startPosition, "testMergeInside: Did not receive correct startPosition"); LiveUnit.Assert.areEqual(3, result[0].length, "testMergeInside: Did not receive correct length"); var testMergeOverlap = [{ startPosition: 20, length: 5 }, { startPosition: 18, length: 5 }]; result = AutoSuggestBox._sortAndMergeHits(testMergeOverlap); LiveUnit.Assert.areEqual(1, result.length, "testMergeOverlap : Did not receive correct number of results"); LiveUnit.Assert.areEqual(18, result[0].startPosition, "testMergeOverlap : Did not receive correct startPosition"); LiveUnit.Assert.areEqual(7, result[0].length, "testMergeOverlap: Did not receive correct length"); var testMergeAdjacent = [{ startPosition: 20, length: 2 }, { startPosition: 17, length: 3 }]; result = AutoSuggestBox._sortAndMergeHits(testMergeAdjacent); LiveUnit.Assert.areEqual(1, result.length, "testMergeAdjacent : Did not receive correct number of results"); LiveUnit.Assert.areEqual(17, result[0].startPosition, "testMergeAdjacent : Did not receive correct startPosition"); LiveUnit.Assert.areEqual(5, result[0].length, "testMergeAdjacent: Did not receive correct length"); } test428216() { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; var eventsCalled = []; asb.addEventListener(AutoSuggestBox._EventNames.querychanged, function (ev) { eventsCalled.push(AutoSuggestBox._EventNames.querychanged); }); var inputElement = asb._inputElement; //mock msGetInputContext so we can have more control over the events var endOffset = 0; inputElement.msGetInputContext = function () { return { getCompositionAlternatives: function () { return []; }, getCandidateWindowClientRect: function () { return { bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0 }; }, compositionEndOffset: endOffset, compositionStartOffset: 0 } }; // When using IME: compositionstart -> compositionupdate -> input -> compositionupdate -> input -> compositionend inputElement.value = 'a'; inputElement.dispatchEvent(createCustomEvent("compositionstart")); inputElement.dispatchEvent(createCustomEvent("compositionupdate")); inputElement.dispatchEvent(createCustomEvent("input")); endOffset++; inputElement.value += 'b'; inputElement.dispatchEvent(createCustomEvent("compositionupdate")); inputElement.dispatchEvent(createCustomEvent("input")); inputElement.dispatchEvent(createCustomEvent("compositionend")); LiveUnit.Assert.areEqual(2, eventsCalled.length, "queryChanged was called more than twice"); } testKoreanIMEKeyboarding() { // Korean keyboarding - IME will finalize on keydown for up/down/enter/tab so make sure we discard the composition end event var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; var inputElement = asb._inputElement var that = this; var changedEventFired = false; asb.addEventListener("querychanged", function asbTest_queryChanged_listener(event) { LiveUnit.Assert.isFalse(changedEventFired, "Querychanged fired multiple times"); changedEventFired = true; }); var submittedEventFired = false; asb.addEventListener("querysubmitted", function asbTest_querySubmitted_listener(event) { LiveUnit.Assert.isFalse(submittedEventFired, "QuerySubmitted fired multiple times"); submittedEventFired = true; }); // Enter key LiveUnit.LoggingCore.logComment("Testing Enter key."); changedEventFired = false; inputElement.value = 'a'; mockInputContext(inputElement, 1, 1, []); inputElement.dispatchEvent(createCustomEvent("compositionstart")); inputElement.dispatchEvent(createCustomEvent("compositionupdate")); inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.isTrue(changedEventFired, "QueryChanged event was not fired"); submittedEventFired = false; Helper.keydown(inputElement, Key.enter, "ko"); LiveUnit.Assert.isTrue(submittedEventFired, "QuerySubmitted event was not fired"); // make sure this event is filtered out (Korean IME finalized on key down event, but still passes key to app) changedEventFired = false; mockInputContext(inputElement, 0, 0, []); inputElement.dispatchEvent(createCustomEvent("compositionend")); LiveUnit.Assert.isFalse(changedEventFired, "QueryChanged event was fired"); Helper.keyup(inputElement, Key.enter, "ko"); // ensure query events are still fired after key is released changedEventFired = false; inputElement.value = 'ab'; inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.isTrue(changedEventFired, "QueryChanged event was not fired"); // Up/Down/Tab keys var keys = [Key.upArrow, Key.downArrow, Key.tab]; for (var i = 0; i < keys.length; i++) { var key = keys[i]; LiveUnit.LoggingCore.logComment("Testing " + key + " key."); changedEventFired = false; inputElement.value = 'a'; mockInputContext(inputElement, 1, 1, []); inputElement.dispatchEvent(createCustomEvent("compositionstart")); inputElement.dispatchEvent(createCustomEvent("compositionupdate")); inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.isTrue(changedEventFired, "QueryChanged event was not fired"); Helper.keydown(inputElement, key, "ko"); // make sure this event is filtered out (Korean IME finalized on key down event, but still passes key to app) changedEventFired = false; mockInputContext(inputElement, 0, 0, []); inputElement.dispatchEvent(createCustomEvent("compositionend")); LiveUnit.Assert.isFalse(changedEventFired, "QueryChanged event was fired"); Helper.keyup(inputElement, key, "ko"); // ensure query events are still fired after key is released changedEventFired = false; inputElement.value = 'ab'; inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.isTrue(changedEventFired, "QueryChanged event was not fired"); } } testQueryChangeAfterFocusLoss(complete) { // Ensure after a focus loss on tab/enter that we still get query change events var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; var inputElement = asb._inputElement; var that = this; var otherInputElement = document.createElement("input"); otherInputElement.type = "text"; document.body.appendChild(otherInputElement); var changedEventFired = false; asb.addEventListener("querychanged", function asbTest_queryChanged_listener(event) { LiveUnit.Assert.isFalse(changedEventFired, "Querychanged fired multiple times"); changedEventFired = true; }); // make sure the input actually has focus, otherwise we don't get the focusout event inputElement.focus(); LiveUnit.Assert.areEqual(inputElement, document.activeElement); var keys = [Key.tab, Key.enter, Key.upArrow, Key.downArrow]; // only Tab (always moves focus) & Enter (if apps handles QuerySubmitted and moves focus) are actually expected to occur; include up/down for test completeness only function runTest(key) { return WinJS.Promise.wrap().then(function () { LiveUnit.LoggingCore.logComment("Testing " + key + " key."); Helper.keydown(inputElement, key, "en-US"); otherInputElement.focus(); return WinJS.Promise.timeout(); }).then(function () { LiveUnit.Assert.areEqual(otherInputElement, document.activeElement); // key up event goes to another control & never reaches inputElement Helper.keyup(otherInputElement, key, "en-US"); // now put focus back inputElement.focus(); return WinJS.Promise.timeout(); }).then(function () { LiveUnit.Assert.areEqual(inputElement, document.activeElement); // ensure query events are still fired changedEventFired = false; inputElement.value = 'a' + key; inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.isTrue(changedEventFired, "QueryChanged event was not fired"); }); } runTest(Key.tab).then(function () { return runTest(Key.enter); }).then(function () { return runTest(Key.upArrow); }).then(function () { return runTest(Key.downArrow); }).done(function () { document.body.removeChild(otherInputElement); complete(); }); } testQueryChangeAfterIMEEaten() { // Ensure after the IME ate the enter/tab keys that we still get query change events var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; var inputElement = asb._inputElement; var that = this; var changedEventFired = false; asb.addEventListener("querychanged", function asbTest_queryChanged_listener(event) { LiveUnit.Assert.isFalse(changedEventFired, "Querychanged fired multiple times"); changedEventFired = true; }); // make sure the input actually has focus, otherwise we don't get the focusout event inputElement.focus(); LiveUnit.Assert.areEqual(inputElement, document.activeElement); var key = Key.enter; LiveUnit.LoggingCore.logComment("Testing " + key + " key."); Helper.keydown(inputElement, key, "zh-Hans-CN"); // key up event was eaten by the IME (actually due to Trident bug BLUE:394522) // ensure query events are still fired changedEventFired = false; inputElement.value = 'a' + key; inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.isTrue(changedEventFired, "QueryChanged event was not fired"); } testBasicLinguisticAlternatives() { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; var inputElement = asb._inputElement; var eventFired = false; var eventQueryText = null; var eventLinguisticDetails = null; asb.addEventListener("querychanged", function asbTest_queryChanged_listener(event) { LiveUnit.Assert.isNotNull(event); LiveUnit.Assert.isNotNull(event.detail); LiveUnit.Assert.isNotNull(event.detail.queryText); eventQueryText = event.detail.queryText; LiveUnit.Assert.isNotNull(event.detail.linguisticDetails); eventLinguisticDetails = event.detail.linguisticDetails; LiveUnit.Assert.isFalse(eventFired, "Querychanged fired multiple times"); eventFired = true; }); // no alternatives case (but has composition string) inputElement.value = 'ab'; mockInputContext(inputElement, 1, 2, []); inputElement.dispatchEvent(createCustomEvent("compositionstart")); inputElement.dispatchEvent(createCustomEvent("compositionupdate")); inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.isTrue(eventFired, "QueryChanged event was not fired"); LiveUnit.Assert.areEqual("ab", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 1, 1, []); // simple alternative case inputElement.value = 'ab'; mockInputContext(inputElement, 0, 2, ['c', 'df', 'ghi']); eventFired = false; inputElement.dispatchEvent(createCustomEvent("compositionupdate")); LiveUnit.Assert.isTrue(eventFired, "QueryChanged event was not fired"); LiveUnit.Assert.areEqual("ab", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 0, 2, ['c', 'df', 'ghi']); // alternatives with finalized text (substitution) case inputElement.value = 'precompsuffix'; mockInputContext(inputElement, 3, 7, ['c', 'df', 'ghi', 'same', 'longer']); eventFired = false; inputElement.dispatchEvent(createCustomEvent("compositionupdate")); LiveUnit.Assert.isTrue(eventFired, "QueryChanged event was not fired"); LiveUnit.Assert.areEqual("precompsuffix", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 3, 4, ['precsuffix', 'predfsuffix', 'preghisuffix', 'presamesuffix', 'prelongersuffix']); } testBasicIMEConversion() { // IME chooses a candidate, get a string change during finalize, alternatives go away var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; var inputElement = asb._inputElement; var eventFired = false; var eventQueryText = null; var eventLinguisticDetails = null; asb.addEventListener("querychanged", function asbTest_queryChanged_listener(event) { LiveUnit.Assert.isNotNull(event); LiveUnit.Assert.isNotNull(event.detail); LiveUnit.Assert.isNotNull(event.detail.queryText); eventQueryText = event.detail.queryText; LiveUnit.Assert.isNotNull(event.detail.linguisticDetails); eventLinguisticDetails = event.detail.linguisticDetails; LiveUnit.Assert.isFalse(eventFired, "Querychanged fired multiple times"); eventFired = true; }); inputElement.value = ''; mockInputContext(inputElement, 0, 0, []); eventFired = false; inputElement.dispatchEvent(createCustomEvent("compositionstart")); LiveUnit.Assert.isFalse(eventFired, "QueryChanged event was incorrectly fired"); inputElement.value = 'b'; mockInputContext(inputElement, 0, 1, ['c', 'd']); eventFired = false; inputElement.dispatchEvent(createCustomEvent("compositionupdate")); LiveUnit.Assert.isTrue(eventFired, "QueryChanged event was not fired"); LiveUnit.Assert.areEqual("b", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 0, 1, ['c', 'd']); inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.areEqual("b", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 0, 1, ['c', 'd']); inputElement.value = 'f'; // conversion mockInputContext(inputElement, 0, 1, []); // still composition at this step eventFired = false; inputElement.dispatchEvent(createCustomEvent("compositionupdate")); LiveUnit.Assert.isTrue(eventFired, "QueryChanged event was not fired"); LiveUnit.Assert.areEqual("f", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 0, 1, []); inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.areEqual("f", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 0, 1, []); inputElement.value = 'f'; mockInputContext(inputElement, 0, 0, []); // composition ended eventFired = false; inputElement.dispatchEvent(createCustomEvent("compositionend")); LiveUnit.Assert.areEqual("f", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 0, 0, []); } testFinalizeAndSubmitWithAlternatives() { // IMEs that keep alternatives on enter to finalize if there is no string change, and keep on submit (JPN, CHS, CHT Bopomofo) var that = this; var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; var inputElement = asb._inputElement; var eventFired = false; var eventQueryText = null; var eventLinguisticDetails = null; asb.addEventListener("querychanged", function asbTest_queryChanged_listener(event) { LiveUnit.Assert.isNotNull(event); LiveUnit.Assert.isNotNull(event.detail); LiveUnit.Assert.isNotNull(event.detail.queryText); eventQueryText = event.detail.queryText; LiveUnit.Assert.isNotNull(event.detail.linguisticDetails); eventLinguisticDetails = event.detail.linguisticDetails; LiveUnit.Assert.isFalse(eventFired, "Querychanged fired multiple times"); eventFired = true; }); var submitEventFired = false; var submitEventQueryText = null; var submitEventLinguisticDetails = null; asb.addEventListener("querysubmitted", function asbTest_querySubmitted_listener(event) { LiveUnit.Assert.isNotNull(event); LiveUnit.Assert.isNotNull(event.detail); LiveUnit.Assert.isNotNull(event.detail.queryText); submitEventQueryText = event.detail.queryText; LiveUnit.Assert.isNotNull(event.detail.linguisticDetails); submitEventLinguisticDetails = event.detail.linguisticDetails; LiveUnit.Assert.isFalse(submitEventFired, "Querychanged fired multiple times"); submitEventFired = true; }); inputElement.value = ''; mockInputContext(inputElement, 0, 0, []); eventFired = false; inputElement.dispatchEvent(createCustomEvent("compositionstart")); LiveUnit.Assert.isFalse(eventFired, "QueryChanged event was incorrectly fired"); inputElement.value = 'bcompd'; mockInputContext(inputElement, 1, 5, ['x', 'y', 'z']); eventFired = false; inputElement.dispatchEvent(createCustomEvent("compositionupdate")); LiveUnit.Assert.isTrue(eventFired, "QueryChanged event was not fired"); LiveUnit.Assert.areEqual("bcompd", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 1, 4, ['bxd', 'byd', 'bzd']); inputElement.value = 'bcompd'; inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.areEqual("bcompd", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 1, 4, ['bxd', 'byd', 'bzd']); inputElement.value = 'bcompd'; mockInputContext(inputElement, 0, 0, ['x', 'y', 'z']); // composition ended, but alternatives kept eventFired = false; inputElement.dispatchEvent(createCustomEvent("compositionend")); LiveUnit.Assert.areEqual("bcompd", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 0, 0, ['bxd', 'byd', 'bzd']); inputElement.value = 'bcompd'; inputElement.dispatchEvent(createCustomEvent("input")); LiveUnit.Assert.areEqual("bcompd", eventQueryText); verifyLinguisticDetails(eventLinguisticDetails, 0, 0, ['bxd', 'byd', 'bzd']); // user submits via enter key submitEventFired = false; Helper.keydown(asb._inputElement, Key.enter, "ja"); LiveUnit.Assert.isTrue(submitEventFired, "QuerySubmitted event was not fired"); LiveUnit.Assert.areEqual("bcompd", submitEventQueryText); verifyLinguisticDetails(submitEventLinguisticDetails, 0, 0, ['bxd', 'byd', 'bzd']); Helper.keyup(asb._inputElement, Key.enter, "ja"); } testSearchHistoryContext() { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; var testContext = "Test Context"; asb.searchHistoryContext = testContext; LiveUnit.Assert.areEqual(testContext, asb.searchHistoryContext, "Unable to set searchHistoryContext"); } testSearchHistoryDisabled() { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; LiveUnit.LoggingCore.logComment("Waiting for control..."); var testContext = "Test Context"; asb.searchHistoryDisabled = true; LiveUnit.Assert.areEqual(true, asb.searchHistoryDisabled, "Unable to set searchHistoryDisabled"); asb.searchHistoryDisabled = false; LiveUnit.Assert.areEqual(false, asb.searchHistoryDisabled, "Unable to set searchHistoryDisabled"); } testSuggestionsDisplayed(complete) { // Verify whether all suggestions are rendered. var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; LiveUnit.LoggingCore.logComment("Verifying..."); asb.addEventListener("suggestionsrequested", function (e) { e.detail.searchSuggestionCollection.appendQuerySuggestions(["Test query Suggestion1 test", "Test query Suggestion2 test"]); e.detail.searchSuggestionCollection.appendSearchSeparator("Separator"); e.detail.searchSuggestionCollection.appendResultSuggestion("Test result Suggestion3 test", "Query suggestion3 detailed text", "tag3", AutoSuggestBox.createResultSuggestionImage("http://fakeurl"), ""); e.detail.searchSuggestionCollection.appendResultSuggestion("Test result Suggestion4 test", "Query suggestion4 detailed text", "tag4", AutoSuggestBox.createResultSuggestionImage("http://fakeurl"), ""); waitForSuggestionFlyoutRender(asb).done(function () { var suggestion1 = asb._repeater.elementFromIndex(0); LiveUnit.Assert.isTrue((suggestion1.textContent.indexOf("Test query Suggestion1 test") >= 0), "Suggestion1 text is not displayed."); var suggestion2 = asb._repeater.elementFromIndex(1); LiveUnit.Assert.isTrue((suggestion2.textContent.indexOf("Test query Suggestion2 test") >= 0), "Suggestion2 text is not displayed."); var suggestion3 = asb._repeater.elementFromIndex(2); LiveUnit.Assert.isTrue((suggestion3.textContent.indexOf("Separator") >= 0), "Suggestion3 text is not displayed."); var suggestion4 = asb._repeater.elementFromIndex(3); LiveUnit.Assert.isTrue((suggestion4.textContent.indexOf("Test result Suggestion3 test") >= 0), "Suggestion3 text is not displayed."); LiveUnit.Assert.isTrue((suggestion4.textContent.indexOf("Query suggestion3 detailed text") >= 0), "Suggestion3 detailed text is not displayed."); var suggestion5 = asb._repeater.elementFromIndex(4); LiveUnit.Assert.isTrue((suggestion5.textContent.indexOf("Test result Suggestion4 test") >= 0), "Suggestion4 text is not displayed."); LiveUnit.Assert.isTrue((suggestion5.textContent.indexOf("Query suggestion4 detailed text") >= 0), "Suggestion4 detailed text is not displayed."); complete(); }); }); asb._inputElement.value = "a"; asb._inputElement.focus(); } testQuerySuggestionSelected(complete) { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; LiveUnit.LoggingCore.logComment("Verifying..."); asb.addEventListener("querysubmitted", function asbTest_querySubmitted_listener(event) { LiveUnit.Assert.areEqual("Test query Suggestion1 test", event.detail.queryText, "Query text not matching suggestion text"); complete(); }); asb.addEventListener("suggestionsrequested", function (e) { e.detail.searchSuggestionCollection.appendQuerySuggestion("Test query Suggestion1 test"); waitForSuggestionFlyoutRender(asb).done(function () { // Select the first suggestion. Helper.touchDown(asb._repeater.elementFromIndex(0)); Helper.touchUp(asb._repeater.elementFromIndex(0)); }); }); asb._inputElement.value = "a"; asb._inputElement.focus(); } testResultSuggestionSelected(complete) { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; LiveUnit.LoggingCore.logComment("Verifying..."); asb.addEventListener("resultsuggestionchosen", function asbTest_resultsuggestionchosen_listener(event) { LiveUnit.Assert.areEqual("tag3", event.detail.tag, "Query text not matching suggestion tag"); complete(); }); asb.addEventListener("suggestionsrequested", function (e) { e.detail.searchSuggestionCollection.appendResultSuggestion("Test result Suggestion3 test", "Query suggestion3 detailed text", "tag3", AutoSuggestBox.createResultSuggestionImage("http://fakeurl"), ""); waitForSuggestionFlyoutRender(asb).done(function () { // Select the first suggestion. Helper.touchDown(asb._repeater.elementFromIndex(0)); Helper.touchUp(asb._repeater.elementFromIndex(0)); }); }); asb._inputElement.value = "a"; asb._inputElement.focus(); } testSuggestionSelectionWithNarrator(complete) { var expectCallback = false; var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; asb.addEventListener("resultsuggestionchosen", function asbTest_resultsuggestionchosen_listener(event) { if (!expectCallback) { LiveUnit.Assert.fail("unexpected callback"); } complete(); }); asb.addEventListener("suggestionsrequested", function (e) { e.detail.searchSuggestionCollection.appendResultSuggestion("Test result Suggestion3 test", "Query suggestion3 detailed text", "tag3", AutoSuggestBox.createResultSuggestionImage("http://fakeurl"), ""); waitForSuggestionFlyoutRender(asb).done(function () { var element = asb._repeater.elementFromIndex(0); // Simulate mouse/touch scenario - Mouse/Touch go thru pointer events then click event. In this scenario, // the click event should NOT invoke the selection. expectCallback = false; Helper.touchDown(element); element.click(); // Simulate narrator click - Fire click w/o going thru pointer events, here we expect an invocation asb._isFlyoutPointerDown = false; expectCallback = true; element.click(); }); }); asb._inputElement.value = "a"; asb._inputElement.focus(); } testChooseSuggestionOnEnterEnabled(complete) { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; asb.chooseSuggestionOnEnter = true; LiveUnit.LoggingCore.logComment("Verifying..."); asb.addEventListener("querysubmitted", function asbTest_querysubmitted_listener(event) { LiveUnit.Assert.areEqual("Test query Suggestion1 test", event.detail.queryText, "Query text not matching input"); if (!WinJS.Utilities.hasWinRT) { LiveUnit.Assert.areEqual("ja-JP", event.detail.language, "Query text language not matching input"); } complete(); }); asb.addEventListener("suggestionsrequested", function (e) { e.detail.searchSuggestionCollection.appendQuerySuggestion("Test query Suggestion1 test"); WinJS.Utilities._setImmediate(function () { Helper.keydown(asb._inputElement, Key.enter, "ja-JP"); }); }); asb._inputElement.value = "Test query"; asb._inputElement.focus(); } testAttemptingToGetInputContextOnWPDoesNotThrowException() { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; asb._inputElement.msGetInputContext = (): any => { throw "test exception"; }; LiveUnit.Assert.isNull(asb._tryGetInputContext()); } testArrowKeysOnSuggestionFlyout(complete) { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; asb.addEventListener("suggestionsrequested", function (e) { e.detail.searchSuggestionCollection.appendQuerySuggestion("1"); e.detail.searchSuggestionCollection.appendQuerySuggestion("2"); WinJS.Promise.timeout().then(function () { Helper.keydown(asb._inputElement, Key.downArrow); return WinJS.Promise.timeout(); }) .then(function () { LiveUnit.Assert.areEqual(0, document.querySelector(".win-autosuggestbox-flyout").scrollTop); LiveUnit.Assert.areEqual("1", asb.element.querySelector(".win-autosuggestbox-suggestion-selected").textContent); Helper.keydown(asb._inputElement, Key.downArrow); return WinJS.Promise.timeout(); }) .then(function () { LiveUnit.Assert.areEqual("2", asb.element.querySelector(".win-autosuggestbox-suggestion-selected").textContent); Helper.keydown(asb._inputElement, Key.upArrow); return WinJS.Promise.timeout(); }) .done(function () { LiveUnit.Assert.areEqual("1", asb.element.querySelector(".win-autosuggestbox-suggestion-selected").textContent); complete(); }); }); asb._inputElement.value = "Test query"; asb._inputElement.focus(); } testArrowKeysOnSuggestionFlyoutAbove(complete) { var asb: WinJS.UI.PrivateAutoSuggestBox = document.getElementById("ASBID").winControl; asb.element.style.position = "absolute"; asb.element.style.bottom = "0"; asb.addEventListener("suggestionsrequested", function (e) { for (var i = 1; i < 20; i++) { e.detail.searchSuggestionCollection.appendQuerySuggestion("" + i); } WinJS.Promise.timeout().then(function () { Helper.keydown(asb._inputElement, Key.upArrow); return WinJS.Promise.timeout(); }) .then(function () { LiveUnit.Assert.areNotEqual(0, document.querySelector(".win-autosuggestbox-flyout").scrollTop); LiveUnit.Assert.areEqual("1", asb.element.querySelector(".win-autosuggestbox-suggestion-selected").textContent); Helper.keydown(asb._inputElement, Key.upArrow); return WinJS.Promise.timeout(); }) .then(function () { LiveUnit.Assert.areEqual("2", asb.element.querySelector(".win-autosuggestbox-suggestion-selected").textContent); Helper.keydown(asb._inputElement, Key.downArrow); return WinJS.Promise.timeout(); }) .done(function () { LiveUnit.Assert.areEqual("1", asb.element.querySelector(".win-autosuggestbox-suggestion-selected").textContent); complete(); }); }); asb._inputElement.value = "Test query"; asb._inputElement.focus(); } }; } LiveUnit.registerTestClass("AutoSuggestBoxTests.AutoSuggestBoxTests");