michael@0: // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: var gEdit = null; michael@0: michael@0: /*============================================================================= michael@0: Search engine mocking utilities michael@0: =============================================================================*/ michael@0: michael@0: var gEngine = null; michael@0: michael@0: const kSearchEngineName = "Foo"; michael@0: const kSearchEngineURI = chromeRoot + "res/testEngine.xml"; michael@0: michael@0: /* michael@0: * addMockSearchDefault - adds a mock search engine to the top of the engine list. michael@0: */ michael@0: function addMockSearchDefault(aTimeoutMs) { michael@0: let deferred = Promise.defer(); michael@0: let timeoutMs = aTimeoutMs || kDefaultWait; michael@0: let timerID = 0; michael@0: michael@0: function engineAddObserver(aSubject, aTopic, aData) { michael@0: if (aData != "engine-added") michael@0: return; michael@0: michael@0: gEngine = Services.search.getEngineByName(kSearchEngineName); michael@0: Services.obs.removeObserver(engineAddObserver, "browser-search-engine-modified"); michael@0: clearTimeout(timerID); michael@0: gEngine.hidden = false; michael@0: ok(gEngine, "mock engine was added"); michael@0: deferred.resolve(); michael@0: } michael@0: michael@0: if (gEngine) { michael@0: deferred.resolve(); michael@0: return deferred.promise; michael@0: } michael@0: michael@0: timerID = setTimeout(function ids_canceller() { michael@0: Services.obs.removeObserver(engineAddObserver, "browser-search-engine-modified"); michael@0: deferred.reject(new Error("search add timeout")); michael@0: }, timeoutMs); michael@0: michael@0: Services.obs.addObserver(engineAddObserver, "browser-search-engine-modified", false); michael@0: Services.search.addEngine(kSearchEngineURI, Ci.nsISearchEngine.DATA_XML, michael@0: "data:image/x-icon,%00", false); michael@0: return deferred.promise; michael@0: } michael@0: michael@0: /* michael@0: * removeMockSearchDefault - removes mock "Foo" search engine. michael@0: */ michael@0: michael@0: function removeMockSearchDefault(aTimeoutMs) { michael@0: let deferred = Promise.defer(); michael@0: let timeoutMs = aTimeoutMs || kDefaultWait; michael@0: let timerID = 0; michael@0: michael@0: function engineRemoveObserver(aSubject, aTopic, aData) { michael@0: if (aData != "engine-removed") michael@0: return; michael@0: michael@0: clearTimeout(timerID); michael@0: gEngine = null; michael@0: Services.obs.removeObserver(engineRemoveObserver, "browser-search-engine-modified"); michael@0: deferred.resolve(); michael@0: } michael@0: michael@0: if (!gEngine) { michael@0: deferred.resolve(); michael@0: return deferred.promise; michael@0: } michael@0: michael@0: timerID = setTimeout(function ids_canceller() { michael@0: Services.obs.removeObserver(engineRemoveObserver, "browser-search-engine-modified"); michael@0: deferred.reject(new Error("search remove timeout")); michael@0: }, timeoutMs); michael@0: michael@0: Services.obs.addObserver(engineRemoveObserver, "browser-search-engine-modified", false); michael@0: Services.search.removeEngine(gEngine); michael@0: return deferred.promise; michael@0: } michael@0: michael@0: /*============================================================================= michael@0: Test cases michael@0: =============================================================================*/ michael@0: michael@0: function test() { michael@0: waitForExplicitFinish(); michael@0: runTests(); michael@0: } michael@0: michael@0: function setUp() { michael@0: if (!gEdit) michael@0: gEdit = document.getElementById("urlbar-edit"); michael@0: michael@0: yield addTab("about:blank"); michael@0: yield showNavBar(); michael@0: } michael@0: michael@0: function tearDown() { michael@0: Browser.closeTab(Browser.selectedTab, { forceClose: true }); michael@0: } michael@0: michael@0: gTests.push({ michael@0: desc: "search engines update", michael@0: setUp: setUp, michael@0: tearDown: tearDown, michael@0: run: function testSearchEngine() { michael@0: // If the XBL hasn't initialized yet, open the popup so that it will. michael@0: if (gEdit.popup._searches == undefined) { michael@0: gEdit.openPopup(); michael@0: gEdit.closePopup(); michael@0: } michael@0: yield waitForCondition(() => gEdit.popup._searches.itemCount); michael@0: michael@0: let numSearches = gEdit.popup._searches.itemCount; michael@0: function getEngineItem() { michael@0: return gEdit.popup._searches.querySelector("richgriditem[value="+kSearchEngineName+"]"); michael@0: } michael@0: michael@0: yield addMockSearchDefault(); michael@0: is(gEdit.popup._searches.itemCount, numSearches + 1, "added search engine count"); michael@0: ok(getEngineItem(), "added search engine item"); michael@0: michael@0: yield removeMockSearchDefault(); michael@0: is(gEdit.popup._searches.itemCount, numSearches, "normal search engine count"); michael@0: ok(!getEngineItem(), "added search engine item"); michael@0: } michael@0: }); michael@0: michael@0: gTests.push({ michael@0: desc: "display autocomplete while typing, handle enter", michael@0: setUp: setUp, michael@0: tearDown: tearDown, michael@0: run: function testUrlbarTyping() { michael@0: sendElementTap(window, gEdit); michael@0: ok(gEdit.isEditing, "focus urlbar: in editing mode"); michael@0: ok(!gEdit.popup.popupOpen, "focus urlbar: popup not open yet"); michael@0: michael@0: EventUtils.sendString("about:blank", window); michael@0: let opened = yield waitForCondition(() => gEdit.popup.popupOpen); michael@0: ok(opened, "type in urlbar: popup opens"); michael@0: michael@0: EventUtils.synthesizeKey("VK_RETURN", {}, window); michael@0: let closed = yield waitForCondition(() => !gEdit.popup.popupOpen); michael@0: ok(closed, "hit enter in urlbar: popup closes, page loads"); michael@0: ok(!gEdit.isEditing, "hit enter in urlbar: not in editing mode"); michael@0: } michael@0: }); michael@0: michael@0: gTests.push({ michael@0: desc: "Control-Enter in urlbar", michael@0: setUp: setUp, michael@0: tearDown: tearDown, michael@0: run: function () { michael@0: sendElementTap(window, gEdit); michael@0: ok(gEdit.isEditing, "focus urlbar: in editing mode"); michael@0: michael@0: EventUtils.sendString("example", window); michael@0: EventUtils.synthesizeKey("VK_RETURN", { accelKey: true }, window); michael@0: is(gEdit.value, "www.example.com", "Control-enter adds www. and .com"); michael@0: ok(!gEdit.isEditing, "hit enter in urlbar: not in editing mode"); michael@0: } michael@0: }); michael@0: michael@0: gTests.push({ michael@0: desc: "Shift-Enter in urlbar", michael@0: setUp: setUp, michael@0: tearDown: tearDown, michael@0: run: function () { michael@0: sendElementTap(window, gEdit); michael@0: ok(gEdit.isEditing, "focus urlbar: in editing mode"); michael@0: michael@0: EventUtils.sendString("example", window); michael@0: EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true }, window); michael@0: is(gEdit.value, "www.example.net", "Shift-enter adds www. and .net"); michael@0: ok(!gEdit.isEditing, "hit enter in urlbar: not in editing mode"); michael@0: } michael@0: }); michael@0: michael@0: gTests.push({ michael@0: desc: "Control-Shift-Enter in urlbar", michael@0: setUp: setUp, michael@0: tearDown: tearDown, michael@0: run: function () { michael@0: sendElementTap(window, gEdit); michael@0: ok(gEdit.isEditing, "focus urlbar: in editing mode"); michael@0: michael@0: EventUtils.sendString("example", window); michael@0: EventUtils.synthesizeKey("VK_RETURN", { accelKey: true, shiftKey: true }, window); michael@0: is(gEdit.value, "www.example.org", "Shift-enter adds www. and .org"); michael@0: ok(!gEdit.isEditing, "hit enter in urlbar: not in editing mode"); michael@0: } michael@0: }); michael@0: michael@0: gTests.push({ michael@0: desc: "display and select a search with keyboard", michael@0: setUp: setUp, michael@0: tearDown: tearDown, michael@0: run: function testSearchKeyboard() { michael@0: yield addMockSearchDefault(); michael@0: michael@0: yield waitForCondition(() => !Browser.selectedTab.isLoading()); michael@0: michael@0: sendElementTap(window, gEdit); michael@0: ok(gEdit.isEditing, "focus urlbar: in editing mode"); michael@0: ok(!gEdit.popup.popupOpen, "focus urlbar: popup not open yet"); michael@0: michael@0: let search = "mozilla"; michael@0: EventUtils.sendString(search, window); michael@0: yield waitForCondition(() => gEdit.popup.popupOpen); michael@0: michael@0: // XXX We should probably change the keyboard selection behavior entirely, michael@0: // given that it makes little to no sense, but that's a job for a later patch. michael@0: michael@0: EventUtils.synthesizeKey("VK_DOWN", {}, window); michael@0: is(gEdit.popup.selectedIndex, -1, "key select search: no result selected"); michael@0: is(gEdit.popup._searches.selectedIndex, 0, "key select search: first search selected"); michael@0: michael@0: let engines = Services.search.getVisibleEngines(); michael@0: for (let i = 0, max = engines.length - 1; i < max; i++) { michael@0: is(gEdit.popup._searches.selectedIndex, i, "key select search: next index"); michael@0: EventUtils.synthesizeKey("VK_DOWN", {}, window); michael@0: } michael@0: michael@0: let existingValue = gEdit.value; michael@0: EventUtils.synthesizeKey("VK_RETURN", {}, window); michael@0: michael@0: yield waitForCondition(() => gEdit.value != existingValue); michael@0: michael@0: let closed = yield waitForCondition(() => !gEdit.popup.popupOpen); michael@0: ok(closed, "hit enter in urlbar: popup closes, page loads"); michael@0: ok(!gEdit.isEditing, "hit enter in urlbar: not in editing mode"); michael@0: michael@0: let searchSubmission = gEngine.getSubmission(search, null); michael@0: let trimmedSubmission = gEdit.trimValue(searchSubmission.uri.spec); michael@0: is(gEdit.value, trimmedSubmission, "hit enter in urlbar: search conducted"); michael@0: michael@0: yield removeMockSearchDefault(); michael@0: } michael@0: }); michael@0: michael@0: gTests.push({ michael@0: desc: "display and select a search with touch", michael@0: setUp: setUp, michael@0: tearDown: tearDown, michael@0: run: function testUrlbarSearchesTouch() { michael@0: yield addMockSearchDefault(); michael@0: michael@0: yield waitForCondition(() => !Browser.selectedTab.isLoading()); michael@0: michael@0: sendElementTap(window, gEdit); michael@0: ok(gEdit.isEditing, "focus urlbar: in editing mode"); michael@0: ok(!gEdit.popup.popupOpen, "focus urlbar: popup not open yet"); michael@0: michael@0: let search = "mozilla"; michael@0: EventUtils.sendString(search, window); michael@0: yield waitForCondition(() => gEdit.popup.popupOpen); michael@0: michael@0: sendElementTap(window, gEdit.popup._searches.lastChild); michael@0: michael@0: let closed = yield waitForCondition(() => !gEdit.popup.popupOpen); michael@0: ok(closed, "tap search option: popup closes, page loads"); michael@0: ok(!gEdit.isEditing, "tap search option: not in editing mode"); michael@0: michael@0: let searchSubmission = gEngine.getSubmission(search, null); michael@0: let trimmedSubmission = gEdit.trimValue(searchSubmission.uri.spec); michael@0: is(gEdit.value, trimmedSubmission, "tap search option: search conducted"); michael@0: michael@0: yield removeMockSearchDefault(); michael@0: } michael@0: }); michael@0: michael@0: gTests.push({ michael@0: desc: "bug 897131 - url bar update after content tap + edge swipe", michael@0: tearDown: tearDown, michael@0: run: function testUrlbarTyping() { michael@0: let tab = yield addTab("about:mozilla"); michael@0: yield showNavBar(); michael@0: michael@0: sendElementTap(window, gEdit); michael@0: ok(gEdit.isEditing, "focus urlbar: in editing mode"); michael@0: ok(!gEdit.popup.popupOpen, "focus urlbar: popup not open yet"); michael@0: michael@0: EventUtils.sendString("about:blank", window); michael@0: let opened = yield waitForCondition(() => gEdit.popup.popupOpen); michael@0: ok(opened, "type in urlbar: popup opens"); michael@0: michael@0: sendElementTap(window, tab.browser); michael@0: michael@0: let closed = yield waitForCondition(() => !gEdit.popup.popupOpen); michael@0: ok(closed, "autocomplete closed after tap on content"); michael@0: ok(!ContextUI.navbarVisible, "navbar closed"); michael@0: michael@0: let event = document.createEvent("Events"); michael@0: event.initEvent("MozEdgeUICompleted", true, false); michael@0: window.dispatchEvent(event); michael@0: michael@0: ok(ContextUI.navbarVisible, "navbar visible"); michael@0: is(gEdit.value, "about:mozilla", "url bar text refreshed"); michael@0: } michael@0: }); michael@0: michael@0: gTests.push({ michael@0: desc: "Bug 916383 - Invisible autocomplete items selectable by keyboard when 'your results' not shown", michael@0: tearDown: tearDown, michael@0: run: function testBug916383() { michael@0: yield addTab("about:start"); michael@0: yield showNavBar(); michael@0: michael@0: sendElementTap(window, gEdit); michael@0: michael@0: let bookmarkItem = Browser.selectedBrowser.contentWindow.BookmarksStartView._grid.querySelector("richgriditem"); michael@0: // Get the first bookmark item label to make sure it will show up in 'your results' michael@0: let label = bookmarkItem.getAttribute("label"); michael@0: michael@0: EventUtils.sendString(label, window); michael@0: michael@0: let opened = yield waitForCondition(() => gEdit.popup.popupOpen); michael@0: yield waitForCondition(() => gEdit.popup._results.itemCount > 0); michael@0: michael@0: ok(!gEdit.popup.hasAttribute("nomatch"), "'Popup doesnt have nomatch attribute when there are results"); michael@0: ok(gEdit.popup._resultsContainer.getBoundingClientRect().width, "'Your results' are visible"); michael@0: ok(gEdit.popup._results.itemCount > 0, "'Your results' are populated"); michael@0: michael@0: // Append a string to make sure it doesn't match anything in 'your results' michael@0: EventUtils.sendString("zzzzzzzzzzzzzzzzzz", window); michael@0: michael@0: yield waitForCondition(() => gEdit.popup.hasAttribute("nomatch")); michael@0: michael@0: is(gEdit.popup._resultsContainer.getBoundingClientRect().width, 0, "'Your results' are hidden"); michael@0: ok(gEdit.popup._results.itemCount === 0, "'Your results' are empty"); michael@0: michael@0: EventUtils.synthesizeKey("VK_DOWN", {}, window); michael@0: is(gEdit.popup._searches.selectedIndex, 0, "key select search: first search selected"); michael@0: michael@0: EventUtils.synthesizeKey("VK_TAB", {}, window); michael@0: is(gEdit.popup._searches.selectedIndex, 1, "tab key: second search selected"); michael@0: michael@0: EventUtils.synthesizeKey("VK_TAB", { shiftKey: true }, window); michael@0: is(gEdit.popup._searches.selectedIndex, 0, "shift-tab: first search selected"); michael@0: } michael@0: }); michael@0: michael@0: gTests.push({ michael@0: desc: "Bug 891667 - Use up arrow too", michael@0: tearDown: tearDown, michael@0: run: function testBug891667() { michael@0: yield addTab("about:start"); michael@0: yield showNavBar(); michael@0: michael@0: sendElementTap(window, gEdit); michael@0: michael@0: let bookmarkItem = Browser.selectedBrowser.contentWindow.BookmarksStartView._grid.querySelector("richgriditem"); michael@0: // Get the first bookmark item label to make sure it will show up in 'your results' michael@0: let label = bookmarkItem.getAttribute("label"); michael@0: michael@0: EventUtils.sendString(label, window); michael@0: michael@0: yield waitForCondition(() => gEdit.popup.popupOpen); michael@0: yield waitForCondition(() => gEdit.popup._results.itemCount > 0); michael@0: michael@0: ok(gEdit.popup._results.itemCount > 0, "'Your results' populated"); michael@0: michael@0: EventUtils.synthesizeKey("VK_UP", {}, window); michael@0: is(gEdit.popup._results.selectedIndex, 0, "Pressing arrow up selects first item."); michael@0: michael@0: EventUtils.synthesizeKey("VK_BACK_SPACE", {}, window); michael@0: yield waitForEvent(document.getElementById("urlbar-edit"), "input"); michael@0: is(gEdit.popup._results.selectedIndex, -1, "backspace: autocomplete de-selected"); michael@0: } michael@0: }); michael@0: