fix: move BottomNavigation and Tabs to @nativescript-community

Cocoapods no longer required with @nativescript/core out of the box and users are no longer taxed with MaterialTabs even if they didn't use those components.

BREAKING CHANGES

If using `BottomNavigation`, just install `@nativescript-community/ui-material-bottom-navigation` and update your imports to use it. API is exactly the same.

If using `Tabs`, just install `@nativescript-community/ui-material-tabs` and update your imports to use it. API is exactly the same.
This commit is contained in:
Nathan Walker
2021-03-15 20:44:44 -07:00
parent 9a7d3ecb34
commit e62acba792
136 changed files with 0 additions and 11239 deletions

View File

@@ -1,284 +0,0 @@
import * as TKUnit from '../../tk-unit';
import * as helper from '../../ui-helper';
import { Label } from '@nativescript/core/ui/label';
import { StackLayout } from '@nativescript/core/ui/layouts/stack-layout';
import { Frame } from '@nativescript/core/ui/frame';
import { Page } from '@nativescript/core/ui/page';
import { ListView, ItemEventData } from '@nativescript/core/ui/list-view';
import { BottomNavigation, TabContentItem, TabStrip, TabStripItem } from '@nativescript/core';
import { Button } from '@nativescript/core/ui/button';
var ASYNC = 2;
function _createBottomNavigation(): BottomNavigation {
var tabView = new BottomNavigation();
tabView.id = 'BottomNavigation';
return tabView;
}
function _createContentItems(count: number): Array<TabContentItem> {
const items = new Array<TabContentItem>();
for (let i = 0; i < count; i++) {
const label = new Label();
label.text = 'Tab ' + i;
const tabEntry = new TabContentItem();
tabEntry.content = label;
items.push(tabEntry);
}
return items;
}
function _createTabStrip(count: number): TabStrip {
const items = new Array<TabStripItem>();
for (let i = 0; i < count; i++) {
let tabStripEntry = new TabStripItem();
tabStripEntry.title = 'Tab ' + i;
items.push(tabStripEntry);
}
const tabStrip = new TabStrip();
tabStrip.items = items;
return tabStrip;
}
function _createListView(): ListView {
var listView = new ListView();
listView.id = 'ListView';
var items = Array.apply(null, Array(10)).map(function (_, i) {
return i;
});
listView.on(ListView.itemLoadingEvent, function (args: ItemEventData) {
var button = <Button>args.view;
if (!button) {
button = new Button();
button.on(Button.tapEvent, _clickHandlerFactory(args.index));
args.view = button;
}
button.text = 'Button' + args.index;
button.id = button.text;
});
listView.items = items;
return listView;
}
function _clickHandlerFactory(index: number) {
return function () {
var pageFactory = function (): Page {
var detailsLabel = new Label();
detailsLabel.text = 'Details Page ' + index;
var detailsPage = new Page();
detailsPage.id = 'details-page';
detailsPage.content = detailsLabel;
return detailsPage;
};
helper.navigateWithHistory(pageFactory);
};
}
function _createFrameView(): Frame {
const frame = new Frame();
frame.navigate({ create: () => new Page() });
return frame;
}
export function testBackNavigationToTabViewWithNestedFramesShouldWork() {
// https://github.com/NativeScript/NativeScript/issues/6490
const topFrame = Frame.topmost();
let tabViewPage: Page;
let tabView: BottomNavigation;
const pageFactory = function (): Page {
tabView = _createBottomNavigation();
let items = Array<TabContentItem>();
let tabViewitem = new TabContentItem();
// tabViewitem.title = "Item1";
tabViewitem.content = _createFrameView();
items.push(tabViewitem);
let tabViewitem2 = new TabContentItem();
// tabViewitem2.title = "Item2";
tabViewitem2.content = _createFrameView();
items.push(tabViewitem2);
tabView.items = items;
tabView.tabStrip = _createTabStrip(2);
tabViewPage = new Page();
tabViewPage.id = 'tab-view-page';
tabViewPage.content = tabView;
return tabViewPage;
};
helper.waitUntilNavigatedFrom(() => topFrame.navigate(pageFactory), topFrame);
TKUnit.waitUntilReady(() => topFrame.currentPage === tabViewPage);
TKUnit.waitUntilReady(() => tabViewIsFullyLoaded(tabView));
// navigate to a different page
helper.waitUntilNavigatedFrom(() => topFrame.navigate({ create: () => new Page(), animated: false }), topFrame);
// navigate back to the page that hold the tabview with nested frames
topFrame.goBack();
// make sure the app did not crash
TKUnit.waitUntilReady(() => topFrame.navigationQueueIsEmpty());
}
export function testWhenNavigatingBackToANonCachedPageContainingATabViewWithAListViewTheListViewIsThere() {
var topFrame = Frame.topmost();
let tabViewPage: Page;
let tabView: BottomNavigation;
let pageFactory = function (): Page {
tabView = _createBottomNavigation();
let items = Array<TabContentItem>();
let tabViewitem = new TabContentItem();
// tabViewitem.title = "List";
tabViewitem.content = _createListView();
items.push(tabViewitem);
let label = new Label();
label.text = 'About';
let aboutLayout = new StackLayout();
aboutLayout.id = 'AboutLayout';
aboutLayout.addChild(label);
tabViewitem = new TabContentItem();
// tabViewitem.title = "About";
tabViewitem.content = aboutLayout;
items.push(tabViewitem);
tabView.items = items;
tabView.tabStrip = _createTabStrip(2);
tabViewPage = new Page();
tabViewPage.id = 'tab-view-page';
tabViewPage.content = tabView;
return tabViewPage;
};
let rootPage = helper.getCurrentPage();
helper.navigateWithHistory(pageFactory);
TKUnit.waitUntilReady(() => topFrame.currentPage === tabViewPage);
TKUnit.waitUntilReady(() => tabViewIsFullyLoaded(tabView));
// This will navigate to a details page. The wait is inside the method.
_clickTheFirstButtonInTheListViewNatively(tabView);
Frame.goBack();
TKUnit.waitUntilReady(() => topFrame.navigationQueueIsEmpty()); //() => topFrame.currentPage === tabViewPage);
Frame.goBack();
TKUnit.waitUntilReady(() => topFrame.currentPage === rootPage);
TKUnit.assert(tabView.items[0].content instanceof ListView, 'ListView should be created when navigating back to the main page.');
}
function tabViewIsFullyLoaded(tabView: BottomNavigation): boolean {
if (!tabView.isLoaded) {
return false;
}
const i = tabView.selectedIndex;
if (i >= 0 && !tabView.items[i].isLoaded) {
return false;
}
if (tabView.android) {
const bottomNavigationBar = <org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar;
if (bottomNavigationBar.getItemCount() === 0) {
return false;
}
}
return true;
}
export function testLoadedAndUnloadedAreFired_WhenNavigatingAwayAndBack() {
let topFrame = Frame.topmost();
let rootPage = helper.getCurrentPage();
let itemCount = 2;
let loadedEventsCount = [0, 0];
let unloadedEventsCount = [0, 0];
const tabView = _createBottomNavigation();
tabView.items = _createContentItems(itemCount);
tabView.tabStrip = _createTabStrip(itemCount);
function createLoadedFor(tabIndex: number) {
return function () {
loadedEventsCount[tabIndex] = loadedEventsCount[tabIndex] + 1;
};
}
function createUnloadedFor(tabIndex: number) {
return function () {
unloadedEventsCount[tabIndex] = unloadedEventsCount[tabIndex] + 1;
};
}
tabView.items.forEach((item, i) => {
item.content.on('loaded', createLoadedFor(i));
item.content.on('unloaded', createUnloadedFor(i));
});
const tabViewPage = new Page();
helper.navigateWithHistory(() => {
tabViewPage.content = tabView;
return tabViewPage;
});
TKUnit.waitUntilReady(() => tabViewIsFullyLoaded(tabView), ASYNC);
const detailsPage = new Page();
helper.navigateWithHistory(() => detailsPage);
TKUnit.assertEqual(topFrame.currentPage, detailsPage);
helper.goBack();
TKUnit.assertEqual(topFrame.currentPage, tabViewPage);
for (let i = 0; i < itemCount; i++) {
tabView.items[i].content.off('loaded');
tabView.items[i].content.off('unloaded');
}
helper.goBack();
TKUnit.assertEqual(topFrame.currentPage, rootPage);
topFrame.currentPage.id = null;
TKUnit.arrayAssert(loadedEventsCount, [2, 0]);
TKUnit.arrayAssert(unloadedEventsCount, [1, 0]);
}
function _clickTheFirstButtonInTheListViewNatively(tabView: BottomNavigation) {
if (tabView.android) {
const androidListView = <android.widget.ListView>tabView.items[0].content.nativeView;
// var viewPager: android.support.v4.view.ViewPager = (<any>tabView)._viewPager;
// var androidListView = <android.widget.ListView>viewPager.getChildAt(0);
var stackLayout = <org.nativescript.widgets.StackLayout>androidListView.getChildAt(0);
var button = <android.widget.Button>stackLayout.getChildAt(0);
button.performClick();
} else {
const tableView = <UITableView>tabView.ios.selectedViewController.view.subviews[0];
const cell = <UITableViewCell>tableView.cellForRowAtIndexPath(NSIndexPath.indexPathForItemInSection(0, 0));
const btn = <UIButton>cell.contentView.subviews[0];
btn.sendActionsForControlEvents(UIControlEvents.TouchUpInside);
}
}

View File

@@ -1,177 +0,0 @@
import * as TKUnit from '../../tk-unit';
import { isAndroid } from '@nativescript/core/platform';
import { _resetRootView } from '@nativescript/core/application/';
import { Frame, NavigationEntry } from '@nativescript/core/ui/frame';
import { Page } from '@nativescript/core/ui/page';
// import { TabView, TabViewItem } from "@nativescript/core/ui/tab-view";
import { BottomNavigation, TabContentItem, TabStrip, TabStripItem } from '@nativescript/core';
function waitUntilNavigatedToMaxTimeout(pages: Page[], action: Function) {
const maxTimeout = 8;
let completed = 0;
function navigatedTo(args) {
args.object.page.off('navigatedTo', navigatedTo);
completed++;
}
pages.forEach((page) => page.on('navigatedTo', navigatedTo));
action();
TKUnit.waitUntilReady(() => completed === pages.length, maxTimeout);
}
function waitUntilTabViewReady(page: Page, action: Function) {
action();
if (isAndroid) {
TKUnit.waitUntilReady(() => page.frame._currentEntry.fragment.isAdded());
} else {
TKUnit.waitUntilReady(() => page.isLoaded);
}
}
function createPage(i: number) {
const page = new Page();
page.id = `Tab${i} Frame${i} Page${i}`;
return page;
}
function createFrame(i: number, page: Page) {
const frame = new Frame();
frame.navigate(() => page);
frame.id = `Tab${i} Frame${i}`;
return frame;
}
function createTabItem(i: number, frame: Frame) {
const tabEntry = new TabContentItem();
// tabEntry.title = "Tab " + i;
tabEntry.content = frame;
tabEntry['index'] = i;
return tabEntry;
}
function createTabItemsWithFrames(count: number) {
const items = [];
for (var i = 0; i < count; i++) {
const page = createPage(i);
const frame = createFrame(i, page);
const tabItem = createTabItem(i, frame);
items.push({ page, frame, tabItem });
}
return items;
}
function createTabStrip(count: number): TabStrip {
const items = new Array<TabStripItem>();
for (let i = 0; i < count; i++) {
let tabStripEntry = new TabStripItem();
tabStripEntry.title = 'Tab ' + i;
items.push(tabStripEntry);
}
const tabStrip = new TabStrip();
tabStrip.items = items;
return tabStrip;
}
export function test_frame_topmost_matches_selectedIndex() {
const items = createTabItemsWithFrames(3);
const tabView = new BottomNavigation();
tabView.items = items.map((item) => item.tabItem);
tabView.tabStrip = createTabStrip(3);
// iOS cannot preload tab items
// Android preloads 1 tab item to the sides by default
// set this to 0, so that both platforms behave the same.
// tabView.androidOffscreenTabLimit = 0;
const entry: NavigationEntry = {
create: () => tabView,
};
waitUntilNavigatedToMaxTimeout([items[0].page], () => _resetRootView(entry));
TKUnit.assertEqual(Frame.topmost().id, 'Tab0 Frame0');
waitUntilNavigatedToMaxTimeout([items[1].page], () => (tabView.selectedIndex = 1));
TKUnit.assertEqual(Frame.topmost().id, 'Tab1 Frame1');
}
export function test_no_preloading_on_index_change() {
let actualEventsRaised = [];
function resetActualEventsRaised() {
for (var i = 0; i < actualEventsRaised.length; i++) {
actualEventsRaised[i] = [];
}
}
function attachEventHandlers(i: number, item) {
actualEventsRaised.push([]);
const page = item.page;
page.on(Page.loadedEvent, () => actualEventsRaised[i].push(`${page.id} loaded`));
page.on(Page.unloadedEvent, () => actualEventsRaised[i].push(`${page.id} unloaded`));
page.on(Page.navigatingToEvent, () => actualEventsRaised[i].push(`${page.id} navigatingTo`));
page.on(Page.navigatingFromEvent, () => actualEventsRaised[i].push(`${page.id} navigatingFrom`));
page.on(Page.navigatedToEvent, () => actualEventsRaised[i].push(`${page.id} navigatedTo`));
page.on(Page.navigatedFromEvent, () => actualEventsRaised[i].push(`${page.id} navigatedFrom`));
const frame = item.frame;
frame.on(Frame.loadedEvent, () => actualEventsRaised[i].push(`${frame.id} loaded`));
frame.on(Frame.unloadedEvent, () => actualEventsRaised[i].push(`${frame.id} unloaded`));
}
const items = createTabItemsWithFrames(3);
items.forEach((item, i) => {
attachEventHandlers(i, item);
});
const tabView = new BottomNavigation();
tabView.items = items.map((item) => item.tabItem);
tabView.tabStrip = createTabStrip(3);
const entry: NavigationEntry = {
create: () => tabView,
};
waitUntilNavigatedToMaxTimeout([items[0].page], () => _resetRootView(entry));
const expectedEventsRaisedAfterTabCreated = [['Tab0 Frame0 loaded', 'Tab0 Frame0 Page0 navigatingTo', 'Tab0 Frame0 Page0 loaded', 'Tab0 Frame0 Page0 navigatedTo'], [], []];
TKUnit.assertDeepEqual(actualEventsRaised, expectedEventsRaisedAfterTabCreated);
resetActualEventsRaised();
waitUntilNavigatedToMaxTimeout([items[2].page], () => (tabView.selectedIndex = 2));
const expectedEventsRaisedAfterSelectThirdTab = [['Tab0 Frame0 Page0 unloaded', 'Tab0 Frame0 unloaded'], [], ['Tab2 Frame2 loaded', 'Tab2 Frame2 Page2 navigatingTo', 'Tab2 Frame2 Page2 loaded', 'Tab2 Frame2 Page2 navigatedTo']];
TKUnit.assertDeepEqual(actualEventsRaised, expectedEventsRaisedAfterSelectThirdTab);
resetActualEventsRaised();
waitUntilTabViewReady(items[0].page, () => (tabView.selectedIndex = 0));
const expectedEventsRaisedAfterReturnToFirstTab = [['Tab0 Frame0 Page0 loaded', 'Tab0 Frame0 loaded'], [], ['Tab2 Frame2 Page2 unloaded', 'Tab2 Frame2 unloaded']];
TKUnit.assertDeepEqual(actualEventsRaised, expectedEventsRaisedAfterReturnToFirstTab);
}
export function tearDownModule() {
const page = new Page();
const frame = new Frame();
frame.navigate(() => page);
const entry: NavigationEntry = {
create: () => frame,
};
waitUntilNavigatedToMaxTimeout([page], () => _resetRootView(entry));
}

View File

@@ -1,40 +0,0 @@
import { BottomNavigation } from '@nativescript/core/ui/bottom-navigation';
export function getNativeTabCount(tabView: BottomNavigation): number {
// there is no native tab content view implementation for Android Bottom Navigation
return tabView.items.length;
}
export function selectNativeTab(tabView: BottomNavigation, index: number): void {
const bottomNavigationBar = <org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar;
if (bottomNavigationBar) {
bottomNavigationBar.setSelectedPosition(index);
}
}
export function getNativeSelectedIndex(tabView: BottomNavigation): number {
// there is no native tab content view implementation for Android Bottom Navigation
return tabView.selectedIndex;
}
export function getNativeFont(tabView: BottomNavigation): any {
const tv: android.widget.TextView = (<org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar).getTextViewForItemAt(0);
if (tv) {
return {
typeface: tv.getTypeface(),
size: tv.getTextSize(),
};
}
return null;
}
export function getOriginalFont(tabView: BottomNavigation): any {
const tv: android.widget.TextView = (<org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar).getTextViewForItemAt(0);
return {
typeface: tv.getTypeface(),
size: tv.getTextSize(),
};
}

View File

@@ -1,8 +0,0 @@
//@private
import { BottomNavigation } from '@nativescript/core/ui/bottom-navigation';
export function getNativeTabCount(tabView: BottomNavigation): number;
export function selectNativeTab(tabView: BottomNavigation, index: number): void;
export function getNativeSelectedIndex(tabView: BottomNavigation): number;
export function getNativeFont(tabView: BottomNavigation): any;
export function getOriginalFont(tabView: BottomNavigation): any;

View File

@@ -1,35 +0,0 @@
import tabViewModule = require('@nativescript/core/ui/tab-view');
import { Font } from '@nativescript/core/ui/styling/font';
export function getNativeTabCount(tabView: tabViewModule.TabView): number {
if (!tabView.ios.viewControllers) {
return 0;
}
return tabView.ios.viewControllers.count;
}
export function selectNativeTab(tabView: tabViewModule.TabView, index: number): void {
tabView.ios.selectedIndex = index;
tabView.ios.delegate.tabBarControllerDidSelectViewController(tabView.ios, tabView.ios.selectedViewController);
}
export function getNativeSelectedIndex(tabView: tabViewModule.TabView): number {
return tabView.ios.selectedIndex;
}
export function getNativeFont(tabView: tabViewModule.TabView): UIFont {
const tabBar = <UITabBar>tabView.ios.tabBar;
if (tabBar.items.count > 0) {
const currentAttrs = tabBar.items[0].titleTextAttributesForState(UIControlState.Normal);
if (currentAttrs) {
return currentAttrs.objectForKey(NSFontAttributeName);
}
}
return null;
}
export function getOriginalFont(tabView: tabViewModule.TabView): UIFont {
return (tabView.style.fontInternal || Font.default).getUIFont(UIFont.systemFontOfSize(10));
}

View File

@@ -1,33 +0,0 @@
import { Image, Label, BottomNavigation, Builder, TabContentItem, TabStrip, TabStripItem } from '@nativescript/core/ui';
import * as TKUnit from '../../tk-unit';
export function test_lowercase_declaration() {
const root = Builder.parse(`
<bottom-navigation>
<tab-strip id="tab-strip">
<tab-strip-item id="tab-strip-item">
<image src="res://icon" id="tab-strip-item-image" />
<label text="test" id="tab-strip-item-label" />
</tab-strip-item>
</tab-strip>
<tab-content-item id="tab-content-item">
<label text="test" id="tab-content-item-label" />
</tab-content-item>
</bottom-navigation>
`);
const tabStrip = root.getViewById('tab-strip');
const tabStripItem = root.getViewById('tab-strip-item');
const tabStripItemImage = root.getViewById('tab-strip-item-image');
const tabStripItemLabel = root.getViewById('tab-strip-item-label');
const tabContentItem = root.getViewById('tab-content-item');
const tabContentItemLabel = root.getViewById('tab-content-item-label');
TKUnit.assert(root instanceof BottomNavigation, 'Expected result: BottomNavigation!; Actual result: ' + root);
TKUnit.assert(tabStrip instanceof TabStrip, 'Expected result: TabStrip!; Actual result: ' + tabStrip);
TKUnit.assert(tabStripItem instanceof TabStripItem, 'Expected result: TabStripItem!; Actual result: ' + tabStripItem);
TKUnit.assert(tabStripItemImage instanceof Image, 'Expected result: Image!; Actual result: ' + tabStripItemImage);
TKUnit.assert(tabStripItemLabel instanceof Label, 'Expected result: Label!; Actual result: ' + tabStripItemLabel);
TKUnit.assert(tabContentItem instanceof TabContentItem, 'Expected result: TabContentItem!; Actual result: ' + tabContentItem);
TKUnit.assert(tabContentItemLabel instanceof Label, 'Expected result: Label!; Actual result: ' + tabContentItemLabel);
}

View File

@@ -1,347 +0,0 @@
import { UITest } from '../../ui-test';
import { Label } from '@nativescript/core/ui/label';
import * as TKUnit from '../../tk-unit';
import * as helper from '../../ui-helper';
import * as tabViewTestsNative from './bottom-navigation-tests-native';
import { BottomNavigation, TabContentItem, TabStrip, TabStripItem, SelectedIndexChangedEventData } from '@nativescript/core';
export class BottomNavigationTest extends UITest<BottomNavigation> {
public create(): BottomNavigation {
var tabView = new BottomNavigation();
tabView.id = 'TabView';
return tabView;
}
// public test_recycling() {
// const setters = new Map<string, Array<any>>();
// setters.set("items", this._createItems(3));
// helper.nativeView_recycling_test(() => new BottomNavigation(), null, null, setters);
// }
_createContentItems(count: number): Array<TabContentItem> {
const items = new Array<TabContentItem>();
for (let i = 0; i < count; i++) {
const label = new Label();
label.text = 'Tab ' + i;
const tabEntry = new TabContentItem();
tabEntry.content = label;
items.push(tabEntry);
}
return items;
}
_createTabStrip(count: number): TabStrip {
const items = new Array<TabStripItem>();
for (let i = 0; i < count; i++) {
let tabStripEntry = new TabStripItem();
tabStripEntry.title = 'Tab ' + i;
items.push(tabStripEntry);
}
const tabStrip = new TabStrip();
tabStrip.items = items;
return tabStrip;
}
public tearDown() {
if (this.testView && this.testView.items) {
this.testView.items.length = 0;
}
super.tearDown();
}
public waitUntilSelectedItemIsFullyLoaded(): boolean {
const tabView = this.testView;
if (!tabView.isLoaded) {
return false;
}
const i = tabView.selectedIndex;
if (i >= 0 && !tabView.items[i].isLoaded) {
return false;
}
if (tabView.android) {
const bottomNavigationBar = <org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar;
if (bottomNavigationBar.getItemCount() === 0) {
return false;
}
}
return true;
}
public test_when_created_items_are_undefined = function () {
TKUnit.assertEqual(this.testView.items, undefined, 'Items should be undefined initally.');
};
public test_when_created_selected_index_is_undefined = function () {
TKUnit.assertEqual(this.testView.selectedIndex, -1, 'selectedIndex should be undefined initally.');
};
// TODO: Do we need this test?
public test_when_setting_items_to_non_empty_array_the_same_amount_of_native_tabs_is_created = function () {
this.testView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
let expectedValue = this.testView.items.length;
let actualValue = tabViewTestsNative.getNativeTabCount(this.testView);
TKUnit.assertEqual(actualValue, expectedValue, 'NativeItems not equal to JS items.');
};
// TODO: Do we need this test?
public test_when_setting_items_to_empty_array_zero_native_tabs_are_created = function () {
var tabView = this.testView;
tabView.items = [];
this.waitUntilTestElementIsLoaded();
var expectedValue = tabView.items.length;
var actualValue = tabViewTestsNative.getNativeTabCount(tabView);
TKUnit.assertEqual(actualValue, expectedValue, 'Should have 0 native tabs.');
};
public test_selected_index_becomes_zero_when_items_bound_to_non_empty_array = function () {
var tabView = this.testView;
// var items = [];
// var StackLayout0 = new StackLayout();
// var label0 = new Label();
// label0.text = "Tab 0";
// StackLayout0.addChild(label0);
// var tabEntry0 = new TabContentItem();
// // tabEntry0.title = "Tab 0";
// tabEntry0.view = StackLayout0;
// items.push(tabEntry0);
// var StackLayout1 = new StackLayout();
// var label1 = new Label();
// label1.text = "Tab 1";
// StackLayout1.addChild(label1);
// var tabEntry1 = new TabContentItem();
// // tabEntry1.title = "Tab 1";
// tabEntry1.view = StackLayout1;
// items.push(tabEntry1);
tabView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
var expectedValue = 0;
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'When bound selectedIndex should be 0.');
};
public test_selected_index_becomes_undefined_when_items_bound_to_empty_array = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
tabView.selectedIndex = 4;
tabView.items = [];
var expectedValue = -1;
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'selectedIndex should be undefined.');
};
public test_selected_index_becomes_undefined_when_items_set_to_undefined = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
// tabView.selectedIndex = 4;
tabView.items = undefined;
var expectedValue = -1;
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'selectedIndex should be undefined.');
};
public test_selected_index_becomes_undefined_when_items_set_to_null = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
tabView.selectedIndex = 4;
this.waitUntilTestElementIsLoaded();
tabView.items = null;
var expectedValue = -1;
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'selectedIndex should be undefined.');
};
public test_items_is_resolved_correctly_if_set_before_view_is_loaded = function () {
var tabView = this.testView;
var expectedValue = 5;
tabView.items = this._createContentItems(expectedValue);
tabView.selectedIndex = 4;
this.waitUntilTestElementIsLoaded();
var actualValue = tabView.items.length;
TKUnit.assertEqual(actualValue, expectedValue, 'items.length should be 5');
};
public test_selected_index_is_resolved_correctly_if_set_before_view_is_loaded = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
var expectedValue = 4;
tabView.selectedIndex = expectedValue;
this.waitUntilTestElementIsLoaded();
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'selectedIndex');
};
public test_binding_to_tabitem_with_undefined_view_should_throw = function () {
var tabView = this.testView;
this.waitUntilTestElementIsLoaded();
TKUnit.assertThrows(() => {
let item = new TabContentItem();
// item.title = "Tab 0";
item.content = undefined;
tabView.items = [item];
}, 'Binding TabNavigation to a TabItem with undefined view should throw.');
};
public test_binding_to_tabitem_with_null_view_should_throw = function () {
var tabView = this.testView;
this.waitUntilTestElementIsLoaded();
TKUnit.assertThrows(() => {
let item = new TabContentItem();
// item.title = "Tab 0";
item.content = null;
tabView.items = [item];
}, 'Binding TabNavigation to a TabItem with null view should throw.');
};
public test_when_selecting_tab_natively_selectedIndex_is_updated_properly = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(2);
tabView.tabStrip = this._createTabStrip(2);
this.waitUntilTestElementIsLoaded();
var expectedValue = 1;
tabViewTestsNative.selectNativeTab(tabView, expectedValue);
TKUnit.waitUntilReady(function () {
return tabView.selectedIndex === expectedValue;
}, helper.ASYNC);
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'selectedIndex');
};
public test_when_selecting_tab_natively_selectedIndexChangedEvent_is_raised = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
tabView.tabStrip = this._createTabStrip(5);
this.waitUntilTestElementIsLoaded();
var expectedOldIndex = 3;
var expectedNewIndex = 4;
var actualOldIndex;
var actualNewIndex;
tabViewTestsNative.selectNativeTab(tabView, expectedOldIndex);
TKUnit.waitUntilReady(function () {
return tabView.selectedIndex === expectedOldIndex;
}, helper.ASYNC);
tabView.on(BottomNavigation.selectedIndexChangedEvent, (args: SelectedIndexChangedEventData) => {
actualOldIndex = args.oldIndex;
actualNewIndex = args.newIndex;
});
tabViewTestsNative.selectNativeTab(tabView, expectedNewIndex);
TKUnit.waitUntilReady(function () {
return tabView.selectedIndex === expectedNewIndex;
}, helper.ASYNC);
TKUnit.assertEqual(actualOldIndex, expectedOldIndex, 'expectedOldIndex');
TKUnit.assertEqual(actualNewIndex, expectedNewIndex, 'expectedNewIndex');
};
// TODO: Do we need this test?
public test_when_setting_selectedIndex_programatically_selectedIndexChangedEvent_is_raised = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
var expectedOldIndex = 2;
var expectedNewIndex = 4;
var actualOldIndex;
var actualNewIndex;
tabView.selectedIndex = expectedOldIndex;
TKUnit.waitUntilReady(function () {
return tabViewTestsNative.getNativeSelectedIndex(tabView) === expectedOldIndex;
}, helper.ASYNC);
tabView.on(BottomNavigation.selectedIndexChangedEvent, (args: SelectedIndexChangedEventData) => {
actualOldIndex = args.oldIndex;
actualNewIndex = args.newIndex;
TKUnit.assertEqual(args.object, tabView, 'args.object should be TabView');
});
tabView.selectedIndex = expectedNewIndex;
TKUnit.waitUntilReady(function () {
return tabViewTestsNative.getNativeSelectedIndex(tabView) === expectedNewIndex;
}, helper.ASYNC);
TKUnit.assertEqual(actualOldIndex, expectedOldIndex, 'expectedOldIndex');
TKUnit.assertEqual(actualNewIndex, expectedNewIndex, 'expectedNewIndex');
};
// TODO: fonts are not yet supported
// public test_font_is_reapplied_when_tab_items_change = function () {
// const assertFontsAreEqual = (actual: any, expected: any, message?: string) => {
// if (this.testView.ios) {
// TKUnit.assertEqual(actual, expected, message);
// } else {
// TKUnit.assertEqual(actual.typeface, expected.typeface, `${message} [typeface]`);
// TKUnit.assertEqual(actual.size, expected.size, `${message} [size]`);
// }
// }
// this.testView.items = this._createContentItems(1);
// this.testView.tabStrip = this._createTabStrip(1);
// this.waitUntilSelectedItemIsFullyLoaded();
// const originalFont = tabViewTestsNative.getOriginalFont(this.testView);
// TKUnit.assertNotNull(originalFont, "Original Font should be applied");
// this.testView.style.font = "20 Pacifico";
// let nativeFont = tabViewTestsNative.getNativeFont(this.testView);
// TKUnit.assertNotNull(nativeFont, "Native Font should not be null");
// TKUnit.assertNotEqual(originalFont, nativeFont, "Font should be changed");
// this.testView.items = this._createContentItems(2);
// this.testView.tabStrip = this._createTabStrip(2);
// this.waitUntilSelectedItemIsFullyLoaded();
// assertFontsAreEqual(tabViewTestsNative.getNativeFont(this.testView), nativeFont, "Font must be 20 Pacifico after rebinding items.");
// this.testView.style.font = "bold 12 monospace";
// nativeFont = tabViewTestsNative.getNativeFont(this.testView);
// this.testView.items = this._createContentItems(3);
// this.testView.tabStrip = this._createTabStrip(3);
// this.waitUntilSelectedItemIsFullyLoaded();
// assertFontsAreEqual(tabViewTestsNative.getNativeFont(this.testView), nativeFont, "Font must be bold 12 monospace after rebinding items.");
// this.testView.style.font = unsetValue;
// assertFontsAreEqual(tabViewTestsNative.getNativeFont(this.testView), originalFont, "Font must be the original one after resetting the style.");
// }
}
export function createTestCase(): BottomNavigationTest {
return new BottomNavigationTest();
}

View File

@@ -1,284 +0,0 @@
import * as TKUnit from '../../tk-unit';
import * as helper from '../../ui-helper';
import { Label } from '@nativescript/core/ui/label';
import { StackLayout } from '@nativescript/core/ui/layouts/stack-layout';
import { Frame } from '@nativescript/core/ui/frame';
import { Page } from '@nativescript/core/ui/page';
import { ListView, ItemEventData } from '@nativescript/core/ui/list-view';
import { Tabs, TabContentItem, TabStrip, TabStripItem } from '@nativescript/core/ui/tabs';
import { Button } from '@nativescript/core/ui/button';
var ASYNC = 2;
function _createTabsNavigation(): Tabs {
var tabView = new Tabs();
tabView.id = 'BottomNavigation';
return tabView;
}
function _createContentItems(count: number): Array<TabContentItem> {
const items = new Array<TabContentItem>();
for (let i = 0; i < count; i++) {
const label = new Label();
label.text = 'Tab ' + i;
const tabEntry = new TabContentItem();
tabEntry.content = label;
items.push(tabEntry);
}
return items;
}
function _createTabStrip(count: number): TabStrip {
const items = new Array<TabStripItem>();
for (let i = 0; i < count; i++) {
let tabStripEntry = new TabStripItem();
tabStripEntry.title = 'Tab ' + i;
items.push(tabStripEntry);
}
const tabStrip = new TabStrip();
tabStrip.items = items;
return tabStrip;
}
function _createListView(): ListView {
var listView = new ListView();
listView.id = 'ListView';
var items = Array.apply(null, Array(10)).map(function (_, i) {
return i;
});
listView.on(ListView.itemLoadingEvent, function (args: ItemEventData) {
var button = <Button>args.view;
if (!button) {
button = new Button();
button.on(Button.tapEvent, _clickHandlerFactory(args.index));
args.view = button;
}
button.text = 'Button' + args.index;
button.id = button.text;
});
listView.items = items;
return listView;
}
function _clickHandlerFactory(index: number) {
return function () {
var pageFactory = function (): Page {
var detailsLabel = new Label();
detailsLabel.text = 'Details Page ' + index;
var detailsPage = new Page();
detailsPage.id = 'details-page';
detailsPage.content = detailsLabel;
return detailsPage;
};
helper.navigateWithHistory(pageFactory);
};
}
function _createFrameView(): Frame {
const frame = new Frame();
frame.navigate({ create: () => new Page() });
return frame;
}
export function testBackNavigationToTabViewWithNestedFramesShouldWork() {
// https://github.com/NativeScript/NativeScript/issues/6490
const topFrame = Frame.topmost();
let tabViewPage: Page;
let tabView: Tabs;
const pageFactory = function (): Page {
tabView = _createTabsNavigation();
let items = Array<TabContentItem>();
let tabViewitem = new TabContentItem();
// tabViewitem.title = "Item1";
tabViewitem.content = _createFrameView();
items.push(tabViewitem);
let tabViewitem2 = new TabContentItem();
// tabViewitem2.title = "Item2";
tabViewitem2.content = _createFrameView();
items.push(tabViewitem2);
tabView.items = items;
tabView.tabStrip = _createTabStrip(2);
tabViewPage = new Page();
tabViewPage.id = 'tab-view-page';
tabViewPage.content = tabView;
return tabViewPage;
};
helper.waitUntilNavigatedFrom(() => topFrame.navigate(pageFactory), topFrame);
TKUnit.waitUntilReady(() => topFrame.currentPage === tabViewPage);
TKUnit.waitUntilReady(() => tabViewIsFullyLoaded(tabView));
// navigate to a different page
helper.waitUntilNavigatedFrom(() => topFrame.navigate({ create: () => new Page(), animated: false }), topFrame);
// navigate back to the page that hold the tabview with nested frames
topFrame.goBack();
// make sure the app did not crash
TKUnit.waitUntilReady(() => topFrame.navigationQueueIsEmpty());
}
export function testWhenNavigatingBackToANonCachedPageContainingATabViewWithAListViewTheListViewIsThere() {
var topFrame = Frame.topmost();
let tabViewPage: Page;
let tabView: Tabs;
let pageFactory = function (): Page {
tabView = _createTabsNavigation();
let items = Array<TabContentItem>();
let tabViewitem = new TabContentItem();
// tabViewitem.title = "List";
tabViewitem.content = _createListView();
items.push(tabViewitem);
let label = new Label();
label.text = 'About';
let aboutLayout = new StackLayout();
aboutLayout.id = 'AboutLayout';
aboutLayout.addChild(label);
tabViewitem = new TabContentItem();
// tabViewitem.title = "About";
tabViewitem.content = aboutLayout;
items.push(tabViewitem);
tabView.items = items;
tabView.tabStrip = _createTabStrip(2);
tabViewPage = new Page();
tabViewPage.id = 'tab-view-page';
tabViewPage.content = tabView;
return tabViewPage;
};
let rootPage = helper.getCurrentPage();
helper.navigateWithHistory(pageFactory);
TKUnit.waitUntilReady(() => topFrame.currentPage === tabViewPage);
TKUnit.waitUntilReady(() => tabViewIsFullyLoaded(tabView));
// This will navigate to a details page. The wait is inside the method.
_clickTheFirstButtonInTheListViewNatively(tabView);
Frame.goBack();
TKUnit.waitUntilReady(() => topFrame.navigationQueueIsEmpty()); //() => topFrame.currentPage === tabViewPage);
Frame.goBack();
TKUnit.waitUntilReady(() => topFrame.currentPage === rootPage);
TKUnit.assert(tabView.items[0].content instanceof ListView, 'ListView should be created when navigating back to the main page.');
}
function tabViewIsFullyLoaded(tabView: Tabs): boolean {
if (!tabView.isLoaded) {
return false;
}
const i = tabView.selectedIndex;
if (i >= 0 && !tabView.items[i].isLoaded) {
return false;
}
if (tabView.android) {
const bottomNavigationBar = <org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar;
if (bottomNavigationBar && bottomNavigationBar.getItemCount() === 0) {
return false;
}
}
return true;
}
export function testLoadedAndUnloadedAreFired_WhenNavigatingAwayAndBack() {
let topFrame = Frame.topmost();
let rootPage = helper.getCurrentPage();
let itemCount = 2;
let loadedEventsCount = [0, 0];
let unloadedEventsCount = [0, 0];
const tabView = _createTabsNavigation();
tabView.items = _createContentItems(itemCount);
tabView.tabStrip = _createTabStrip(itemCount);
function createLoadedFor(tabIndex: number) {
return function () {
loadedEventsCount[tabIndex] = loadedEventsCount[tabIndex] + 1;
};
}
function createUnloadedFor(tabIndex: number) {
return function () {
unloadedEventsCount[tabIndex] = unloadedEventsCount[tabIndex] + 1;
};
}
tabView.items.forEach((item, i) => {
item.content.on('loaded', createLoadedFor(i));
item.content.on('unloaded', createUnloadedFor(i));
});
const tabViewPage = new Page();
helper.navigateWithHistory(() => {
tabViewPage.content = tabView;
return tabViewPage;
});
TKUnit.waitUntilReady(() => tabViewIsFullyLoaded(tabView), ASYNC);
const detailsPage = new Page();
helper.navigateWithHistory(() => detailsPage);
TKUnit.assertEqual(topFrame.currentPage, detailsPage);
helper.goBack();
TKUnit.assertEqual(topFrame.currentPage, tabViewPage);
for (let i = 0; i < itemCount; i++) {
tabView.items[i].content.off('loaded');
tabView.items[i].content.off('unloaded');
}
helper.goBack();
TKUnit.assertEqual(topFrame.currentPage, rootPage);
topFrame.currentPage.id = null;
TKUnit.arrayAssert(loadedEventsCount, [2, 2]);
TKUnit.arrayAssert(unloadedEventsCount, [1, 1]);
}
function _clickTheFirstButtonInTheListViewNatively(tabView: Tabs) {
if (tabView.android) {
const androidListView = <android.widget.ListView>tabView.items[0].content.nativeView;
// var viewPager: android.support.v4.view.ViewPager = (<any>tabView)._viewPager;
// var androidListView = <android.widget.ListView>viewPager.getChildAt(0);
var stackLayout = <org.nativescript.widgets.StackLayout>androidListView.getChildAt(0);
var button = <android.widget.Button>stackLayout.getChildAt(0);
button.performClick();
} else {
const tableView = <UITableView>tabView.viewController.viewControllers[0].view.subviews[0];
const cell = <UITableViewCell>tableView.cellForRowAtIndexPath(NSIndexPath.indexPathForItemInSection(0, 0));
const btn = <UIButton>cell.contentView.subviews[0];
btn.sendActionsForControlEvents(UIControlEvents.TouchUpInside);
}
}

View File

@@ -1,194 +0,0 @@
import * as TKUnit from '../../tk-unit';
import { Page, Frame, Tabs, TabContentItem, TabStrip, TabStripItem, NavigationEntry, Application } from '@nativescript/core';
function waitUntilNavigatedToMaxTimeout(pages: Page[], action: Function) {
const maxTimeout = 8;
let completed = 0;
function navigatedTo(args) {
args.object.page.off('navigatedTo', navigatedTo);
completed++;
}
pages.forEach((page) => page.on('navigatedTo', navigatedTo));
action();
TKUnit.waitUntilReady(() => completed === pages.length, maxTimeout);
}
function createPage(i: number) {
const page = new Page();
page.id = `Tab${i} Frame${i} Page${i}`;
return page;
}
function createFrame(i: number, page: Page) {
const frame = new Frame();
frame.navigate(() => page);
frame.id = `Tab${i} Frame${i}`;
return frame;
}
function createTabItem(i: number, frame: Frame) {
const tabEntry = new TabContentItem();
// tabEntry.title = "Tab " + i;
tabEntry.content = frame;
tabEntry['index'] = i;
return tabEntry;
}
function createTabItemsWithFrames(count: number) {
const items = [];
for (var i = 0; i < count; i++) {
const page = createPage(i);
const frame = createFrame(i, page);
const tabItem = createTabItem(i, frame);
items.push({ page, frame, tabItem });
}
return items;
}
function createTabStrip(count: number): TabStrip {
const items = new Array<TabStripItem>();
for (let i = 0; i < count; i++) {
let tabStripEntry = new TabStripItem();
tabStripEntry.title = 'Tab ' + i;
items.push(tabStripEntry);
}
const tabStrip = new TabStrip();
tabStrip.items = items;
return tabStrip;
}
export function test_frame_topmost_matches_selectedIndex() {
const items = createTabItemsWithFrames(3);
const tabView = new Tabs();
tabView.items = items.map((item) => item.tabItem);
tabView.tabStrip = createTabStrip(3);
// iOS cannot preload tab items
// Android preloads 1 tab item to the sides by default
// set this to 0, so that both platforms behave the same.
// tabView.androidOffscreenTabLimit = 0;
const entry: NavigationEntry = {
create: () => tabView,
};
waitUntilNavigatedToMaxTimeout([items[0].page], () => Application.resetRootView(entry));
TKUnit.assertEqual(Frame.topmost().id, 'Tab0 Frame0');
waitUntilNavigatedToMaxTimeout([items[1].page], () => (tabView.selectedIndex = 1));
TKUnit.assertEqual(Frame.topmost().id, 'Tab1 Frame1');
}
// TODO: _resetRootView doesn't work with TabView or Tabs with pre-loading. The fragments that are removed crash the app with missing reference.
// export function test_preloading_one_to_the_side_on_index_change() {
// let actualEventsRaised = [];
// function resetActualEventsRaised() {
// for (var i = 0; i < actualEventsRaised.length; i++) {
// actualEventsRaised[i] = [];
// }
// }
// function attachEventHandlers(i: number, item) {
// actualEventsRaised.push([]);
// const page = item.page;
// page.on(Page.loadedEvent, () => actualEventsRaised[i].push(`${page.id} loaded`));
// page.on(Page.unloadedEvent, () => actualEventsRaised[i].push(`${page.id} unloaded`));
// page.on(Page.navigatingToEvent, () => actualEventsRaised[i].push(`${page.id} navigatingTo`));
// page.on(Page.navigatingFromEvent, () => actualEventsRaised[i].push(`${page.id} navigatingFrom`));
// page.on(Page.navigatedToEvent, () => actualEventsRaised[i].push(`${page.id} navigatedTo`));
// page.on(Page.navigatedFromEvent, () => actualEventsRaised[i].push(`${page.id} navigatedFrom`));
// const frame = item.frame;
// frame.on(Frame.loadedEvent, () => actualEventsRaised[i].push(`${frame.id} loaded`));
// frame.on(Frame.unloadedEvent, () => actualEventsRaised[i].push(`${frame.id} unloaded`));
// }
// const items = createTabItemsWithFrames(3);
// items.forEach((item, i) => {
// attachEventHandlers(i, item);
// });
// const tabView = new Tabs();
// tabView.items = items.map(item => item.tabItem);
// tabView.tabStrip = createTabStrip(3);
// const entry: NavigationEntry = {
// create: () => tabView
// };
// waitUntilNavigatedToMaxTimeout([items[0].page], () => Application.resetRootView(entry));
// const expectedEventsRaisedAfterTabCreated = [
// [
// "Tab0 Frame0 loaded",
// "Tab0 Frame0 Page0 navigatingTo",
// "Tab0 Frame0 Page0 loaded",
// "Tab0 Frame0 Page0 navigatedTo",
// ],
// [],
// []
// ];
// TKUnit.assertDeepEqual(actualEventsRaised, expectedEventsRaisedAfterTabCreated);
// resetActualEventsRaised();
// waitUntilNavigatedToMaxTimeout([items[2].page], () => tabView.selectedIndex = 2);
// const expectedEventsRaisedAfterSelectThirdTab = [
// [
// "Tab0 Frame0 Page0 unloaded",
// "Tab0 Frame0 unloaded",
// ],
// [],
// [
// "Tab2 Frame2 loaded",
// "Tab2 Frame2 Page2 navigatingTo",
// "Tab2 Frame2 Page2 loaded",
// "Tab2 Frame2 Page2 navigatedTo"
// ]
// ];
// TKUnit.assertDeepEqual(actualEventsRaised, expectedEventsRaisedAfterSelectThirdTab);
// resetActualEventsRaised();
// waitUntilTabViewReady(items[0].page, () => tabView.selectedIndex = 0);
// const expectedEventsRaisedAfterReturnToFirstTab = [
// [
// "Tab0 Frame0 Page0 loaded",
// "Tab0 Frame0 loaded",
// ],
// [],
// [
// "Tab2 Frame2 Page2 unloaded",
// "Tab2 Frame2 unloaded",
// ]
// ];
// TKUnit.assertDeepEqual(actualEventsRaised, expectedEventsRaisedAfterReturnToFirstTab);
// }
export function tearDownModule() {
const page = new Page();
const frame = new Frame();
frame.navigate(() => page);
const entry: NavigationEntry = {
create: () => frame,
};
waitUntilNavigatedToMaxTimeout([page], () => Application.resetRootView(entry));
}

View File

@@ -1,40 +0,0 @@
import { BottomNavigation } from '@nativescript/core/ui/bottom-navigation';
export function getNativeTabCount(tabView: BottomNavigation): number {
// there is no native tab content view implementation for Android Bottom Navigation
return tabView.items.length;
}
export function selectNativeTab(tabView: BottomNavigation, index: number): void {
const bottomNavigationBar = <org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar;
if (bottomNavigationBar) {
bottomNavigationBar.setSelectedPosition(index);
}
}
export function getNativeSelectedIndex(tabView: BottomNavigation): number {
// there is no native tab content view implementation for Android Bottom Navigation
return tabView.selectedIndex;
}
export function getNativeFont(tabView: BottomNavigation): any {
const tv: android.widget.TextView = (<org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar).getTextViewForItemAt(0);
if (tv) {
return {
typeface: tv.getTypeface(),
size: tv.getTextSize(),
};
}
return null;
}
export function getOriginalFont(tabView: BottomNavigation): any {
const tv: android.widget.TextView = (<org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar).getTextViewForItemAt(0);
return {
typeface: tv.getTypeface(),
size: tv.getTextSize(),
};
}

View File

@@ -1,8 +0,0 @@
//@private
import { TabView } from '@nativescript/core/ui/tab-view';
export function getNativeTabCount(tabView: TabView): number;
export function selectNativeTab(tabView: TabView, index: number): void;
export function getNativeSelectedIndex(tabView: TabView): number;
export function getNativeFont(tabView: TabView): any;
export function getOriginalFont(tabView: TabView): any;

View File

@@ -1,44 +0,0 @@
import { Tabs } from '@nativescript/core/ui/tabs';
import { Font } from '@nativescript/core/ui/styling/font';
// TODO: Should we add getCount to UIPageViewController???
export function getNativeTabCount(tabView: Tabs): number {
if (!(<any>tabView).viewControllers) {
return 0;
}
return (<any>tabView).viewControllers.length;
}
// TODO: separate in another function with Tabs implementation - selectNativeTab()
export function selectNativeTab(tabView: Tabs, index: number): void {
const item = tabView.items[index];
const controllers = NSMutableArray.alloc<UIViewController>().initWithCapacity(1);
let itemController = (<any>item).__controller;
controllers.addObject(itemController);
let navigationDirection = UIPageViewControllerNavigationDirection.Forward;
tabView.viewController.setViewControllersDirectionAnimatedCompletion(controllers, navigationDirection, false, null);
tabView.viewController.delegate.pageViewControllerDidFinishAnimatingPreviousViewControllersTransitionCompleted(tabView.viewController, true, null, true);
}
// TODO: Should we add getNativeSelectedIndex to UIPageViewController???
export function getNativeSelectedIndex(tabView: Tabs): number {
return tabView.selectedIndex;
}
export function getNativeFont(tabView: Tabs): UIFont {
const tabBar = <UITabBar>tabView.viewController.tabBar;
if (tabBar.items.count > 0) {
const currentAttrs = tabBar.items[0].titleTextAttributesForState(UIControlState.Normal);
if (currentAttrs) {
return currentAttrs.objectForKey(NSFontAttributeName);
}
}
return null;
}
export function getOriginalFont(tabView: Tabs): UIFont {
return (tabView.style.fontInternal || Font.default).getUIFont(UIFont.systemFontOfSize(10));
}

View File

@@ -1,33 +0,0 @@
import { Image, Label, Builder, TabContentItem, Tabs, TabStrip, TabStripItem } from '@nativescript/core/ui';
import * as TKUnit from '../../tk-unit';
export function test_lowercase_declaration() {
const root = Builder.parse(`
<tabs>
<tab-strip id="tab-strip">
<tab-strip-item id="tab-strip-item">
<image src="res://icon" id="tab-strip-item-image" />
<label text="test" id="tab-strip-item-label" />
</tab-strip-item>
</tab-strip>
<tab-content-item id="tab-content-item">
<label text="test" id="tab-content-item-label" />
</tab-content-item>
</tabs>
`);
const tabStrip = root.getViewById('tab-strip');
const tabStripItem = root.getViewById('tab-strip-item');
const tabStripItemImage = root.getViewById('tab-strip-item-image');
const tabStripItemLabel = root.getViewById('tab-strip-item-label');
const tabContentItem = root.getViewById('tab-content-item');
const tabContentItemLabel = root.getViewById('tab-content-item-label');
TKUnit.assert(root instanceof Tabs, 'Expected result: Tabs!; Actual result: ' + root);
TKUnit.assert(tabStrip instanceof TabStrip, 'Expected result: TabStrip!; Actual result: ' + tabStrip);
TKUnit.assert(tabStripItem instanceof TabStripItem, 'Expected result: TabStripItem!; Actual result: ' + tabStripItem);
TKUnit.assert(tabStripItemImage instanceof Image, 'Expected result: Image!; Actual result: ' + tabStripItemImage);
TKUnit.assert(tabStripItemLabel instanceof Label, 'Expected result: Label!; Actual result: ' + tabStripItemLabel);
TKUnit.assert(tabContentItem instanceof TabContentItem, 'Expected result: TabContentItem!; Actual result: ' + tabContentItem);
TKUnit.assert(tabContentItemLabel instanceof Label, 'Expected result: Label!; Actual result: ' + tabContentItemLabel);
}

View File

@@ -1,350 +0,0 @@
import { UITest } from '../../ui-test';
import { Label } from '@nativescript/core/ui/label';
import * as TKUnit from '../../tk-unit';
import * as helper from '../../ui-helper';
import * as tabViewTestsNative from './tabs-tests-native';
import { Tabs, TabContentItem, TabStrip, TabStripItem, SelectedIndexChangedEventData } from '@nativescript/core/ui/tabs';
export class TabsTest extends UITest<Tabs> {
public create(): Tabs {
var tabView = new Tabs();
tabView.id = 'TabView';
return tabView;
}
// public test_recycling() {
// const setters = new Map<string, Array<any>>();
// setters.set("items", this._createItems(3));
// helper.nativeView_recycling_test(() => new BottomNavigation(), null, null, setters);
// }
_createContentItems(count: number): Array<TabContentItem> {
const items = new Array<TabContentItem>();
for (let i = 0; i < count; i++) {
const label = new Label();
label.text = 'Tab ' + i;
const tabEntry = new TabContentItem();
tabEntry.content = label;
items.push(tabEntry);
}
return items;
}
_createTabStrip(count: number): TabStrip {
const items = new Array<TabStripItem>();
for (let i = 0; i < count; i++) {
let tabStripEntry = new TabStripItem();
tabStripEntry.title = 'Tab ' + i;
items.push(tabStripEntry);
}
const tabStrip = new TabStrip();
tabStrip.items = items;
return tabStrip;
}
public tearDown() {
if (this.testView && this.testView.items) {
this.testView.items.length = 0;
}
super.tearDown();
}
public waitUntilSelectedItemIsFullyLoaded(): boolean {
const tabView = this.testView;
if (!tabView.isLoaded) {
return false;
}
const i = tabView.selectedIndex;
if (i >= 0 && !tabView.items[i].isLoaded) {
return false;
}
if (tabView.android) {
const bottomNavigationBar = <org.nativescript.widgets.BottomNavigationBar>(<any>tabView)._bottomNavigationBar;
if (bottomNavigationBar.getItemCount() === 0) {
return false;
}
}
return true;
}
public test_when_created_items_are_undefined = function () {
TKUnit.assertEqual(this.testView.items, undefined, 'Items should be undefined initally.');
};
public test_when_created_selected_index_is_undefined = function () {
TKUnit.assertEqual(this.testView.selectedIndex, -1, 'selectedIndex should be undefined initally.');
};
// TODO: Do we need this test? The number of tabs is dynamic and isn't kept in the native implementation.
// TODO: Maybe test if all native tabBarItems are created.
public test_when_setting_items_to_non_empty_array_the_same_amount_of_native_tabs_is_created = function () {
this.testView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
let expectedValue = this.testView.items.length;
let actualValue = tabViewTestsNative.getNativeTabCount(this.testView);
TKUnit.assertEqual(actualValue, expectedValue, 'NativeItems not equal to JS items.');
};
// TODO: Do we need this test? The number of tabs is dynamic and isn't kept in the native implementation.
// TODO: Maybe test if all native tabBarItems are created.
public test_when_setting_items_to_empty_array_zero_native_tabs_are_created = function () {
var tabView = this.testView;
tabView.items = [];
this.waitUntilTestElementIsLoaded();
var expectedValue = tabView.items.length;
var actualValue = tabViewTestsNative.getNativeTabCount(tabView);
TKUnit.assertEqual(actualValue, expectedValue, 'Should have 0 native tabs.');
};
public test_selected_index_becomes_zero_when_items_bound_to_non_empty_array = function () {
var tabView = this.testView;
// var items = [];
// var StackLayout0 = new StackLayout();
// var label0 = new Label();
// label0.text = "Tab 0";
// StackLayout0.addChild(label0);
// var tabEntry0 = new TabContentItem();
// // tabEntry0.title = "Tab 0";
// tabEntry0.view = StackLayout0;
// items.push(tabEntry0);
// var StackLayout1 = new StackLayout();
// var label1 = new Label();
// label1.text = "Tab 1";
// StackLayout1.addChild(label1);
// var tabEntry1 = new TabContentItem();
// // tabEntry1.title = "Tab 1";
// tabEntry1.view = StackLayout1;
// items.push(tabEntry1);
tabView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
var expectedValue = 0;
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'When bound selectedIndex should be 0.');
};
public test_selected_index_becomes_undefined_when_items_bound_to_empty_array = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
tabView.selectedIndex = 4;
tabView.items = [];
var expectedValue = -1;
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'selectedIndex should be undefined.');
};
public test_selected_index_becomes_undefined_when_items_set_to_undefined = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
// tabView.selectedIndex = 4;
tabView.items = undefined;
var expectedValue = -1;
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'selectedIndex should be undefined.');
};
public test_selected_index_becomes_undefined_when_items_set_to_null = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
tabView.selectedIndex = 4;
this.waitUntilTestElementIsLoaded();
tabView.items = null;
var expectedValue = -1;
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'selectedIndex should be undefined.');
};
public test_items_is_resolved_correctly_if_set_before_view_is_loaded = function () {
var tabView = this.testView;
var expectedValue = 5;
tabView.items = this._createContentItems(expectedValue);
tabView.selectedIndex = 4;
this.waitUntilTestElementIsLoaded();
var actualValue = tabView.items.length;
TKUnit.assertEqual(actualValue, expectedValue, 'items.length should be 5');
};
public test_selected_index_is_resolved_correctly_if_set_before_view_is_loaded = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
var expectedValue = 4;
tabView.selectedIndex = expectedValue;
this.waitUntilTestElementIsLoaded();
var actualValue = tabView.selectedIndex;
TKUnit.assertEqual(actualValue, expectedValue, 'selectedIndex');
};
public test_binding_to_tabitem_with_undefined_view_should_throw = function () {
var tabView = this.testView;
this.waitUntilTestElementIsLoaded();
TKUnit.assertThrows(() => {
let item = new TabContentItem();
// item.title = "Tab 0";
item.content = undefined;
tabView.items = [item];
}, 'Binding TabNavigation to a TabItem with undefined view should throw.');
};
public test_binding_to_tabitem_with_null_view_should_throw = function () {
var tabView = this.testView;
this.waitUntilTestElementIsLoaded();
TKUnit.assertThrows(() => {
let item = new TabContentItem();
// item.title = "Tab 0";
item.content = null;
tabView.items = [item];
}, 'Binding TabNavigation to a TabItem with null view should throw.');
};
// TODO: times out
// public test_when_selecting_tab_natively_selectedIndex_is_updated_properly = function () {
// var tabView = this.testView;
// tabView.items = this._createContentItems(2);
// this.waitUntilTestElementIsLoaded();
// var expectedValue = 1;
// tabViewTestsNative.selectNativeTab(tabView, expectedValue);
// TKUnit.waitUntilReady(function () {
// return tabView.selectedIndex === expectedValue;
// }, helper.ASYNC);
// var actualValue = tabView.selectedIndex;
// TKUnit.assertEqual(actualValue, expectedValue, "selectedIndex");
// }
// TODO: times out
// public test_when_selecting_tab_natively_selectedIndexChangedEvent_is_raised = function () {
// var tabView = this.testView;
// tabView.items = this._createContentItems(5);
// this.waitUntilTestElementIsLoaded();
// var expectedOldIndex = 3;
// var expectedNewIndex = 4;
// var actualOldIndex;
// var actualNewIndex;
// tabViewTestsNative.selectNativeTab(tabView, expectedOldIndex);
// TKUnit.waitUntilReady(function () {
// return tabView.selectedIndex === expectedOldIndex;
// }, 10);
// tabView.on(Tabs.selectedIndexChangedEvent, (args: SelectedIndexChangedEventData) => {
// actualOldIndex = args.oldIndex;
// actualNewIndex = args.newIndex;
// });
// tabViewTestsNative.selectNativeTab(tabView, expectedNewIndex);
// TKUnit.waitUntilReady(function () {
// return tabView.selectedIndex === expectedNewIndex;
// }, helper.ASYNC);
// TKUnit.assertEqual(actualOldIndex, expectedOldIndex, "expectedOldIndex");
// TKUnit.assertEqual(actualNewIndex, expectedNewIndex, "expectedNewIndex");
// }
// TODO: Do we need this test?
public test_when_setting_selectedIndex_programatically_selectedIndexChangedEvent_is_raised = function () {
var tabView = this.testView;
tabView.items = this._createContentItems(5);
this.waitUntilTestElementIsLoaded();
var expectedOldIndex = 2;
var expectedNewIndex = 4;
var actualOldIndex;
var actualNewIndex;
tabView.selectedIndex = expectedOldIndex;
TKUnit.waitUntilReady(function () {
return tabViewTestsNative.getNativeSelectedIndex(tabView) === expectedOldIndex;
}, helper.ASYNC);
tabView.on(Tabs.selectedIndexChangedEvent, (args: SelectedIndexChangedEventData) => {
actualOldIndex = args.oldIndex;
actualNewIndex = args.newIndex;
TKUnit.assertEqual(args.object, tabView, 'args.object should be TabView');
});
tabView.selectedIndex = expectedNewIndex;
TKUnit.waitUntilReady(function () {
return tabViewTestsNative.getNativeSelectedIndex(tabView) === expectedNewIndex;
}, helper.ASYNC);
TKUnit.assertEqual(actualOldIndex, expectedOldIndex, 'expectedOldIndex');
TKUnit.assertEqual(actualNewIndex, expectedNewIndex, 'expectedNewIndex');
};
//TODO: Font styling is not ready
// public test_font_is_reapplied_when_tab_items_change = function () {
// const assertFontsAreEqual = (actual: any, expected: any, message?: string) => {
// if (this.testView.ios) {
// TKUnit.assertEqual(actual, expected, message);
// } else {
// TKUnit.assertEqual(actual.typeface, expected.typeface, `${message} [typeface]`);
// TKUnit.assertEqual(actual.size, expected.size, `${message} [size]`);
// }
// }
// this.testView.items = this._createContentItems(1);
// this.testView.tabStrip = this._createTabStrip(1);
// this.waitUntilSelectedItemIsFullyLoaded();
// const originalFont = tabViewTestsNative.getOriginalFont(this.testView);
// TKUnit.assertNotNull(originalFont, "Original Font should be applied");
// this.testView.style.font = "20 Pacifico";
// let nativeFont = tabViewTestsNative.getNativeFont(this.testView);
// TKUnit.assertNotNull(nativeFont, "Native Font should not be null");
// TKUnit.assertNotEqual(originalFont, nativeFont, "Font should be changed");
// this.testView.items = this._createContentItems(2);
// this.testView.tabStrip = this._createTabStrip(2);
// this.waitUntilSelectedItemIsFullyLoaded();
// assertFontsAreEqual(tabViewTestsNative.getNativeFont(this.testView), nativeFont, "Font must be 20 Pacifico after rebinding items.");
// this.testView.style.font = "bold 12 monospace";
// nativeFont = tabViewTestsNative.getNativeFont(this.testView);
// this.testView.items = this._createContentItems(3);
// this.testView.tabStrip = this._createTabStrip(3);
// this.waitUntilSelectedItemIsFullyLoaded();
// assertFontsAreEqual(tabViewTestsNative.getNativeFont(this.testView), nativeFont, "Font must be bold 12 monospace after rebinding items.");
// this.testView.style.font = unsetValue;
// assertFontsAreEqual(tabViewTestsNative.getNativeFont(this.testView), originalFont, "Font must be the original one after resetting the style.");
// }
}
export function createTestCase(): TabsTest {
return new TabsTest();
}