import TKUnit = require("../../TKUnit"); import helper = require("../helper"); import viewModule = require("ui/core/view"); import labelModule = require("ui/label"); import stackLayoutModule = require("ui/layouts/stack-layout"); import tabViewTestsNative = require("./tab-view-tests-native"); import frameModule = require("ui/frame"); import pageModule = require("ui/page"); import listViewModule = require("ui/list-view"); import buttonModule = require("ui/button"); import observable = require("data/observable"); // // # TabView // ### Declaring the TabView in xml. //```XML // // // // // // // // // // // // // // //``` // Using a TabView requires the "ui/tab-view" module. // ``` JavaScript import tabViewModule = require("ui/tab-view"); // ``` // var ASYNC = 0.3; function _createTabView(): tabViewModule.TabView { // // ## Creating a TabView // ``` JavaScript var tabView = new tabViewModule.TabView(); // ``` // tabView.id = "TabView"; return tabView; } function _createItems(count: number): Array { var items = new Array(); for (var i = 0; i < count; i++) { var label = new labelModule.Label(); label.text = "Tab " + i; var tabEntry = { title: "Tab " + i, view: label }; items.push(tabEntry); } return items; } function _createListView(): listViewModule.ListView { var listView = new listViewModule.ListView(); listView.id = "ListView"; var items = Array.apply(null, Array(10)).map(function (_, i) { return i; }); listView.on(listViewModule.ListView.itemLoadingEvent, function (args: listViewModule.ItemEventData) { var button = args.view; if (!button) { button = new buttonModule.Button(); args.view = button; } button.text = "Button" + args.index; button.id = button.text; button.on(buttonModule.Button.tapEvent, _clickHandlerFactory(args.index)); }); listView.items = items; return listView; } var _clickHandlerFactory = function (index: number) { return function () { var pageFactory = function (): pageModule.Page { var detailsLabel = new labelModule.Label(); detailsLabel.text = "Details Page " + index; var detailsPage = new pageModule.Page(); detailsPage.content = detailsLabel; return detailsPage; }; helper.navigate(pageFactory); } } export var testWhenTabViewIsCreatedItemsAreUndefined = function () { helper.buildUIAndRunTest(_createTabView(), function (views: Array) { var tabView = views[0]; var expectedValue = undefined; var actualValue = tabView.items; TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testWhenTabViewIsCreatedSelectedIndexIsUndefined = function () { helper.buildUIAndRunTest(_createTabView(), function (views: Array) { var tabView = views[0]; var expectedValue = undefined; var actualValue = tabView.selectedIndex; TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testWhenSettingItemsToNonEmptyArrayTheSameAmountOfNativeTabsIsCreated = function () { helper.buildUIAndRunTest(_createTabView(), function (views: Array) { var tabView = views[0]; tabView.items = _createItems(10); var expectedValue = tabView.items.length; var actualValue = tabViewTestsNative.getNativeTabCount(tabView); TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testWhenSettingItemsToEmptyArrayZeroNativeTabsAreCreated = function () { helper.buildUIAndRunTest(_createTabView(), function (views: Array) { var tabView = views[0]; tabView.items = []; var expectedValue = tabView.items.length; var actualValue = tabViewTestsNative.getNativeTabCount(tabView); TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testSelectedIndexBecomesZeroWhenItemsBoundToNonEmptyArray = function () { helper.buildUIAndRunTest(_createTabView(), function (views: Array) { var tabView = views[0]; // // ### Binding TabView.items // ``` JavaScript var items = []; var StackLayout0 = new stackLayoutModule.StackLayout(); var label0 = new labelModule.Label(); label0.text = "Tab 0"; StackLayout0.addChild(label0); var tabEntry0 = { title: "Tab 0", view: StackLayout0 }; items.push(tabEntry0); var StackLayout1 = new stackLayoutModule.StackLayout(); var label1 = new labelModule.Label(); label1.text = "Tab 1"; StackLayout1.addChild(label1); var tabEntry1 = { title: "Tab 1", view: StackLayout1 }; items.push(tabEntry1); tabView.items = items; // ``` // var expectedValue = 0; var actualValue = tabView.selectedIndex; TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testSelectedIndexBecomesUndefinedWhenItemsBoundToEmptyArray = function () { helper.buildUIAndRunTest(_createTabView(), function (views: Array) { var tabView = views[0]; tabView.items = _createItems(10); // // ### Selecting a tab programmatically // ``` JavaScript tabView.selectedIndex = 9; // ``` // tabView.items = []; var expectedValue = undefined; var actualValue = tabView.selectedIndex; TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testSelectedIndexBecomesUndefinedWhenItemsBoundToUndefined = function () { helper.buildUIAndRunTest(_createTabView(), function (views: Array) { var tabView = views[0]; tabView.items = _createItems(10); tabView.selectedIndex = 9; tabView.items = undefined; var expectedValue = undefined; var actualValue = tabView.selectedIndex; TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testSelectedIndexBecomesUndefinedWhenItemsBoundToNull = function () { helper.buildUIAndRunTest(_createTabView(), function (views: Array) { var tabView = views[0]; tabView.items = _createItems(10); tabView.selectedIndex = 9; tabView.items = null; var expectedValue = undefined; var actualValue = tabView.selectedIndex; TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testItemsIsResolvedCorrectlyIfSetBeforeViewIsLoaded = function () { var tabView = _createTabView(); var expectedValue = 10; tabView.items = _createItems(expectedValue); tabView.selectedIndex = 9; helper.buildUIAndRunTest(tabView, function (views: Array) { var tabView = views[0]; var actualValue = tabView.items.length; TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testSelectedIndexIsResolvedCorrectlyIfSetBeforeViewIsLoaded = function () { var tabView = _createTabView(); tabView.items = _createItems(10); var expectedValue = 9; tabView.selectedIndex = expectedValue; helper.buildUIAndRunTest(tabView, function (views: Array) { var tabView = views[0]; var actualValue = tabView.selectedIndex; TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); }); } export var testSettingNegativeSelectedIndexShouldThrow = function () { var tabView = _createTabView(); helper.buildUIAndRunTest(tabView, function (views: Array) { var tabView = views[0]; tabView.items = _createItems(10); TKUnit.assertThrows(function () { tabView.selectedIndex = -1; }, "Setting selectedIndex to a negative number should throw."); }); } export var testSettingSelectedIndexLargerThanCountShouldThrow = function () { var tabView = _createTabView(); helper.buildUIAndRunTest(tabView, function (views: Array) { var tabView = views[0]; tabView.items = _createItems(10); TKUnit.assertThrows(function () { tabView.selectedIndex = 10; }, "Setting selectedIndex to a negative number should throw."); }); } export var testBindingToTabEntryWithUndefinedViewShouldThrow = function () { var tabView = _createTabView(); helper.buildUIAndRunTest(tabView, function (views: Array) { var tabView = views[0]; TKUnit.assertThrows(function () { tabView.items = [{ title: "Tab 0", view: undefined }]; }, "Binding TabView to a TabViewItem with undefined view should throw."); }); } export var testBindingToTabEntryWithNullViewShouldThrow = function () { var tabView = _createTabView(); helper.buildUIAndRunTest(tabView, function (views: Array) { var tabView = views[0]; TKUnit.assertThrows(function () { tabView.items = [{ title: "Tab 0", view: null }]; }, "Binding TabView to a TabViewItem with null view should throw."); }); } export var testWhenSelectingATabNativelySelectedIndexIsUpdatedProperly = function () { var tabView: tabViewModule.TabView; var mainPage: pageModule.Page; var pageFactory = function (): pageModule.Page { tabView = _createTabView(); tabView.items = _createItems(2); mainPage = new pageModule.Page(); mainPage.content = tabView; return mainPage; }; helper.navigate(pageFactory); var expectedValue = 1; tabViewTestsNative.selectNativeTab(tabView, expectedValue); TKUnit.wait(helper.ASYNC); var actualValue = tabView.selectedIndex; try { TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue); } finally { helper.goBack(); } } export var testWhenSelectingATabNativelySelectedIndexChangedEventIsRaised = function () { var tabView: tabViewModule.TabView; var mainPage: pageModule.Page; var pageFactory = function (): pageModule.Page { tabView = _createTabView(); tabView.items = _createItems(10); mainPage = new pageModule.Page(); mainPage.content = tabView; return mainPage; }; helper.navigate(pageFactory); var expectedOldIndex = 3; var expectedNewIndex = 5; var actualOldIndex; var actualNewIndex; tabViewTestsNative.selectNativeTab(tabView, expectedOldIndex); TKUnit.wait(helper.ASYNC); tabView.on(tabViewModule.TabView.selectedIndexChangedEvent,(args: tabViewModule.SelectedIndexChangedEventData) => { actualOldIndex = args.oldIndex; actualNewIndex = args.newIndex; }); tabViewTestsNative.selectNativeTab(tabView, expectedNewIndex); TKUnit.wait(helper.ASYNC); try { TKUnit.assert(actualOldIndex === expectedOldIndex, "Actual: " + actualOldIndex + "; Expected: " + expectedOldIndex); TKUnit.assert(actualNewIndex === expectedNewIndex, "Actual: " + actualNewIndex + "; Expected: " + expectedNewIndex); } finally { helper.goBack(); } } export var testWhenSettingSelectedIndexProgramaticallySelectedIndexChangedEventIsRaised = function () { var tabView: tabViewModule.TabView; var mainPage: pageModule.Page; var pageFactory = function (): pageModule.Page { tabView = _createTabView(); tabView.items = _createItems(10); mainPage = new pageModule.Page(); mainPage.content = tabView; return mainPage; }; helper.navigate(pageFactory); var expectedOldIndex = 2; var expectedNewIndex = 6; var actualOldIndex; var actualNewIndex; tabView.selectedIndex = expectedOldIndex; TKUnit.wait(helper.ASYNC); tabView.on(tabViewModule.TabView.selectedIndexChangedEvent,(args: tabViewModule.SelectedIndexChangedEventData) => { actualOldIndex = args.oldIndex; actualNewIndex = args.newIndex; }); tabView.selectedIndex = expectedNewIndex; TKUnit.wait(helper.ASYNC); try { TKUnit.assert(actualOldIndex === expectedOldIndex, "Actual: " + actualOldIndex + "; Expected: " + expectedOldIndex); TKUnit.assert(actualNewIndex === expectedNewIndex, "Actual: " + actualNewIndex + "; Expected: " + expectedNewIndex); } finally { helper.goBack(); } } export var testWhenNavigatingBackToANonCachedPageContainingATabViewWithAListViewTheListViewIsThere = function () { return; var topFrame = frameModule.topmost(); var oldChache; if (topFrame.android) { oldChache = topFrame.android.cachePagesOnNavigate; topFrame.android.cachePagesOnNavigate = true; } try { var mainPage: pageModule.Page; var pageFactory = function (): pageModule.Page { var tabView = _createTabView(); var items = []; items.push({ title: "List", view: _createListView() }); var label = new labelModule.Label(); label.text = "About"; var aboutLayout = new stackLayoutModule.StackLayout(); aboutLayout.id = "AboutLayout"; aboutLayout.addChild(label); items.push({ title: "About", view: aboutLayout }); tabView.items = items; mainPage = new pageModule.Page(); mainPage.content = tabView; return mainPage; } helper.navigate(pageFactory); var tabView = mainPage.getViewById("TabView"); // This will navigate to a details page. The wait is inside the method. _clickTheFirstButtonInTheListViewNatively(tabView); // Go back to the main page containing the TabView. helper.goBack(); // Go back to the root tests page. helper.goBack(); } finally { if (topFrame.android) { topFrame.android.cachePagesOnNavigate = oldChache; } } var listView = mainPage.getViewById("ListView"); TKUnit.assert(listView !== undefined, "ListView should be created when navigating back to the main page."); } export function testBindingIsRefreshedWhenTabViewItemIsUnselectedAndThenSelectedAgain() { helper.buildUIAndRunTest(_createTabView(), function (views: Array) { var viewModel = new observable.Observable(); viewModel.set("counter", 0); frameModule.topmost().currentPage.bindingContext = viewModel; var tabView = views[0]; var items = _createItems(10); var StackLayout0 = new stackLayoutModule.StackLayout(); var label0 = new labelModule.Label(); label0.text = "Tab 0"; label0.id = "testLabel"; label0.bind({ sourceProperty: "counter", targetProperty: "text", twoWay: true }); StackLayout0.addChild(label0); var tabEntry0 = { title: "Tab 0", view: StackLayout0 }; items.push(tabEntry0); tabView.items = items; tabView.selectedIndex = 10; TKUnit.wait(ASYNC); tabView.selectedIndex = 0; TKUnit.wait(ASYNC); tabView.selectedIndex = 10; TKUnit.wait(ASYNC); var expectedValue = 5; viewModel.set("counter", expectedValue); var testLabel = (tabView.items[10].view.getViewById("testLabel")) TKUnit.assertEqual(testLabel.text, expectedValue, "binding is not working!"); }); } export function testLoadedAndUnloadedAreFired_WhenNavigatingAwayAndBack_NoPageCaching() { testLoadedAndUnloadedAreFired_WhenNavigatingAwayAndBack(false); } export function testLoadedAndUnloadedAreFired_WhenNavigatingAwayAndBack_WithPageCaching() { testLoadedAndUnloadedAreFired_WhenNavigatingAwayAndBack(true); } function testLoadedAndUnloadedAreFired_WhenNavigatingAwayAndBack(enablePageCache: boolean) { var i: number; var itemCount = 3; var loadedItems = [0, 0, 0]; var unloadedItems = [0, 0, 0]; var topFrame = frameModule.topmost(); var oldChache; if (topFrame.android) { oldChache = topFrame.android.cachePagesOnNavigate; topFrame.android.cachePagesOnNavigate = enablePageCache; } try { var tabView = _createTabView(); var items = _createItems(itemCount); tabView.items = items; function createLoadedFor(itemIndex: number) { return function () { loadedItems[itemIndex] = loadedItems[itemIndex] + 1; } } function createUnloadedFor(itemIndex: number) { return function () { unloadedItems[itemIndex] = unloadedItems[itemIndex] + 1; } } helper.buildUIAndRunTest(tabView, function () { try { TKUnit.waitUntilReady(() => { return items[0].view.isLoaded; }, ASYNC); // Attach to loaded/unloaded events for (i = 0; i < itemCount; i++) { items[i].view.on("loaded", createLoadedFor(i)); items[i].view.on("unloaded", createUnloadedFor(i)); } var detailsPageFactory = function (): pageModule.Page { var detailsPage = new pageModule.Page(); detailsPage.content = new labelModule.Label(); return detailsPage; }; helper.navigate(detailsPageFactory); } finally { // Go back to the test page. helper.goBack(); } TKUnit.waitUntilReady(() => { return items[0].view.isLoaded; }, ASYNC); //console.log("loaded items: " + loadedItems.join(", ")); //console.log("unloadedItems items: " + unloadedItems.join(", ")); // Check that at least the first item is loaded and unloaded TKUnit.assert(items[0].view.isLoaded, "Thecontent of the first tab should be loaded."); TKUnit.assertEqual(loadedItems[0], 1, "loaded count for 1st item"); TKUnit.assertEqual(unloadedItems[0], 1, "unloaded count for 1st item"); // Check that loaded/unloaded coutns are equal for all tabs for (i = 0; i < itemCount; i++) { TKUnit.assert(loadedItems[i] === unloadedItems[i], "Loaded and unloaded calls are not equal for item " + i + " loaded: " + loadedItems[i] + " unloaded: " + unloadedItems[i]); } }); } finally { // Return original page cache value if (topFrame.android) { topFrame.android.cachePagesOnNavigate = oldChache; } } } function _clickTheFirstButtonInTheListViewNatively(tabView: tabViewModule.TabView) { if (tabView.android) { var androidListView = tabView.android.getChildAt(0); (androidListView.getChildAt(0)).performClick(); } else { ((tabView.ios.viewControllers[0].view.subviews[0]).cellForRowAtIndexPath(NSIndexPath.indexPathForItemInSection(0, 0)).contentView.subviews[0]).sendActionsForControlEvents(UIControlEvents.UIControlEventTouchUpInside); } }