diff --git a/.travis.yml b/.travis.yml index 9209e2405..704747505 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,3 +39,4 @@ before_script: script: - tns platform add android - tns test android --emulator --justlaunch + - npm run appium-android diff --git a/nativescript-angular/application.ts b/nativescript-angular/application.ts index b80f91776..1e2cb83c7 100644 --- a/nativescript-angular/application.ts +++ b/nativescript-angular/application.ts @@ -3,6 +3,7 @@ import "zone.js/dist/zone-node" import 'reflect-metadata'; import './polyfills/array'; +import {rendererLog, rendererError} from "./trace"; import {SanitizationService} from '@angular/core/src/security'; import {isPresent, Type, print} from '@angular/core/src/facade/lang'; import {ReflectiveInjector, reflector, coreLoadAndBootstrap, createPlatform, @@ -107,18 +108,18 @@ export function nativeScriptBootstrap(appComponentType: any, customProviders?: P let onLoadedHandler = function(args) { page.off('loaded', onLoadedHandler); //profiling.stop('application-start'); - console.log('Page loaded'); + rendererLog('Page loaded'); //profiling.start('ng-bootstrap'); - console.log('BOOTSTRAPPING...'); + rendererLog('BOOTSTRAPPING...'); bootstrap(appComponentType, customProviders).then((appRef) => { //profiling.stop('ng-bootstrap'); - console.log('ANGULAR BOOTSTRAP DONE.'); + rendererLog('ANGULAR BOOTSTRAP DONE.'); resolve(appRef); }, (err) => { - console.log('ERROR BOOTSTRAPPING ANGULAR'); + rendererError('ERROR BOOTSTRAPPING ANGULAR'); let errorMessage = err.message + "\n\n" + err.stack; - console.log(errorMessage); + rendererError(errorMessage); let view = new TextView(); view.text = errorMessage; diff --git a/nativescript-angular/directives/list-view-comp.ts b/nativescript-angular/directives/list-view-comp.ts index ff131b306..5d35d3df2 100644 --- a/nativescript-angular/directives/list-view-comp.ts +++ b/nativescript-angular/directives/list-view-comp.ts @@ -22,6 +22,7 @@ import {View} from 'ui/core/view'; import {NgView} from '../view-util'; import {ObservableArray} from 'data/observable-array'; import {LayoutBase} from 'ui/layouts/layout-base'; +import {rendererLog, rendererError} from "../trace"; const NG_VIEW = "_ngViewRef"; export class ListItemContext { @@ -98,7 +99,7 @@ export class ListViewComponent { let viewRef: EmbeddedViewRef; if (args.view) { - console.log("ListView.onItemLoading: " + index + " - Reusing existing view"); + rendererLog("ListView.onItemLoading: " + index + " - Reusing existing view"); viewRef = args.view[NG_VIEW]; // getting angular view from original element (in cases when ProxyViewContainer is used NativeScript internally wraps it in a StackLayout) if (!viewRef) { @@ -106,7 +107,7 @@ export class ListViewComponent { } } else { - console.log("ListView.onItemLoading: " + index + " - Creating view from template"); + rendererLog("ListView.onItemLoading: " + index + " - Creating view from template"); viewRef = this.loader.createEmbeddedView(this.itemTemplate, new ListItemContext(), 0); args.view = getSingleViewFromViewRef(viewRef); args.view[NG_VIEW] = viewRef; diff --git a/nativescript-angular/directives/tab-view.ts b/nativescript-angular/directives/tab-view.ts index 6700a0d84..c26f2ecf9 100644 --- a/nativescript-angular/directives/tab-view.ts +++ b/nativescript-angular/directives/tab-view.ts @@ -1,6 +1,7 @@ import {ElementRef, Directive, Input, TemplateRef, ViewContainerRef} from "@angular/core"; import {TabView, TabViewItem} from "ui/tab-view"; import * as utils from '../common/utils'; +import {rendererLog, rendererError} from "../trace"; import {isBlank} from '@angular/core/src/facade/lang'; @Directive({ @@ -31,7 +32,7 @@ export class TabViewDirective { ngAfterViewInit() { this.viewInitialized = true; debugger; - console.log("this._selectedIndex: " + this._selectedIndex); + rendererLog("this._selectedIndex: " + this._selectedIndex); if (!isBlank(this._selectedIndex)) { this.tabView.selectedIndex = this._selectedIndex; } diff --git a/nativescript-angular/dom_adapter.ts b/nativescript-angular/dom_adapter.ts index 9a31f6af2..b642957e8 100644 --- a/nativescript-angular/dom_adapter.ts +++ b/nativescript-angular/dom_adapter.ts @@ -3,6 +3,7 @@ import {SanitizationService} from '@angular/core/src/security'; import {Parse5DomAdapter} from '@angular/platform-server'; import {setRootDomAdapter} from '@angular/platform-browser/src/dom/dom_adapter'; import {Type} from '@angular/core/src/facade/lang'; +import {rendererLog, rendererError} from "./trace"; export enum SecurityContext { NONE, @@ -35,7 +36,7 @@ export class NativeScriptSanitizationService extends SanitizationService { export class NativeScriptDomAdapter extends Parse5DomAdapter { static makeCurrent() { - console.log("Setting DOM"); + rendererLog("Setting DOM"); setRootDomAdapter(new NativeScriptDomAdapter()); } diff --git a/nativescript-angular/renderer.ts b/nativescript-angular/renderer.ts index c9cef9aca..7d6c46aa5 100644 --- a/nativescript-angular/renderer.ts +++ b/nativescript-angular/renderer.ts @@ -12,12 +12,11 @@ import {View} from "ui/core/view"; import * as application from "application"; import {topmost} from 'ui/frame'; import {Page} from 'ui/page'; -import {traceLog, ViewUtil, NgView} from "./view-util"; +import {ViewUtil, NgView} from "./view-util"; +import {rendererLog as traceLog} from "./trace"; import {escapeRegexSymbols} from "utils/utils"; import { Device } from "platform"; -export { rendererTraceCategory } from "./view-util"; - @Injectable() export class NativeScriptRootRenderer implements RootRenderer { private _rootView: View = null; diff --git a/nativescript-angular/router/common.ts b/nativescript-angular/router/common.ts deleted file mode 100644 index 2ec488458..000000000 --- a/nativescript-angular/router/common.ts +++ /dev/null @@ -1,7 +0,0 @@ -import trace = require("trace"); - -export const CATEGORY = "ns-router"; - -export function log(message: string) { - trace.write(message, CATEGORY); -} diff --git a/nativescript-angular/router/ns-location-strategy.ts b/nativescript-angular/router/ns-location-strategy.ts index 025989624..4744263ae 100644 --- a/nativescript-angular/router/ns-location-strategy.ts +++ b/nativescript-angular/router/ns-location-strategy.ts @@ -1,7 +1,7 @@ import application = require("application"); import { LocationStrategy } from '@angular/common'; import { NgZone, ApplicationRef, Inject, forwardRef } from '@angular/core'; -import { log } from "./common"; +import { routerLog } from "../trace"; import { topmost } from "ui/frame"; interface LocationState { @@ -20,18 +20,18 @@ export class NSLocationStrategy extends LocationStrategy { private _isPageNavigatingForward: boolean = false; path(): string { - log("NSLocationStrategy.path()"); + routerLog("NSLocationStrategy.path()"); let state = this.peekState(); return state ? state.url : "/"; } prepareExternalUrl(internal: string): string { - log("NSLocationStrategy.prepareExternalUrl() internal: " + internal); + routerLog("NSLocationStrategy.prepareExternalUrl() internal: " + internal); return internal; } pushState(state: any, title: string, url: string, queryParams: string): void { - log(`NSLocationStrategy.pushState state: ${state}, title: ${title}, url: ${url}, queryParams: ${queryParams}`); + routerLog(`NSLocationStrategy.pushState state: ${state}, title: ${title}, url: ${url}, queryParams: ${queryParams}`); let isNewPage = this._isPageNavigatingForward; this._isPageNavigatingForward = false; @@ -46,12 +46,12 @@ export class NSLocationStrategy extends LocationStrategy { } replaceState(state: any, title: string, url: string, queryParams: string): void { - log(`NSLocationStrategy.replaceState state: ${state}, title: ${title}, url: ${url}, queryParams: ${queryParams}`); + routerLog(`NSLocationStrategy.replaceState state: ${state}, title: ${title}, url: ${url}, queryParams: ${queryParams}`); throw new Error("Not implemented"); } forward(): void { - log("NSLocationStrategy.forward"); + routerLog("NSLocationStrategy.forward"); throw new Error("Not implemented"); } @@ -65,17 +65,17 @@ export class NSLocationStrategy extends LocationStrategy { state = this.states.pop(); count++; } - log("NSLocationStrategy.back() while navigating back. States popped: " + count) + routerLog("NSLocationStrategy.back() while navigating back. States popped: " + count) this.callPopState(state, true); } else { let state = this.peekState(); if (state.isPageNavigation) { // This was a page navigation - so navigate through frame. - log("NSLocationStrategy.back() while not navigating back but top state is page - will call frame.goback()") + routerLog("NSLocationStrategy.back() while not navigating back but top state is page - will call frame.goback()") topmost().goBack(); } else { // Nested navigation - just pop the state - log("NSLocationStrategy.back() while not navigating back but top state is not page - just pop") + routerLog("NSLocationStrategy.back() while not navigating back but top state is not page - just pop") this.callPopState(this.states.pop(), true); } } @@ -83,12 +83,12 @@ export class NSLocationStrategy extends LocationStrategy { } onPopState(fn: (_: any) => any): void { - log("NSLocationStrategy.onPopState"); + routerLog("NSLocationStrategy.onPopState"); this.popStateCallbacks.push(fn); } getBaseHref(): string { - log("NSLocationStrategy.getBaseHref()"); + routerLog("NSLocationStrategy.getBaseHref()"); return ""; } @@ -108,7 +108,7 @@ export class NSLocationStrategy extends LocationStrategy { // Methods for syncing with page navigation in PageRouterOutlet public beginBackPageNavigation() { - log("NSLocationStrategy.startGoBack()"); + routerLog("NSLocationStrategy.startGoBack()"); if (this._isPageNavigationgBack) { throw new Error("Calling startGoBack while going back.") } @@ -116,7 +116,7 @@ export class NSLocationStrategy extends LocationStrategy { } public finishBackPageNavigation() { - log("NSLocationStrategy.finishBackPageNavigation()"); + routerLog("NSLocationStrategy.finishBackPageNavigation()"); if (!this._isPageNavigationgBack) { throw new Error("Calling endGoBack while not going back.") } @@ -128,7 +128,7 @@ export class NSLocationStrategy extends LocationStrategy { } public navigateToNewPage() { - log("NSLocationStrategy.navigateToNewPage()"); + routerLog("NSLocationStrategy.navigateToNewPage()"); if (this._isPageNavigatingForward) { throw new Error("Calling navigateToNewPage while already navigating to new page.") } diff --git a/nativescript-angular/router/ns-router-link.ts b/nativescript-angular/router/ns-router-link.ts index e0bd5dd37..77cc90177 100644 --- a/nativescript-angular/router/ns-router-link.ts +++ b/nativescript-angular/router/ns-router-link.ts @@ -1,7 +1,7 @@ import {Directive, Input} from '@angular/core'; import {isString} from '@angular/core/src/facade/lang'; import {Router, Instruction} from '@angular/router-deprecated'; -import { log } from "./common"; +import {routerLog} from "../trace"; /** * The NSRouterLink directive lets you link to specific parts of your app. @@ -55,7 +55,7 @@ export class NSRouterLink { } onTap(): void { - log("NSRouterLink onTap() instruction: " + JSON.stringify(this._navigationInstruction)) + routerLog("NSRouterLink onTap() instruction: " + JSON.stringify(this._navigationInstruction)) this._router.navigateByInstruction(this._navigationInstruction); } } diff --git a/nativescript-angular/router/ns-router.ts b/nativescript-angular/router/ns-router.ts index 3e1bd4d6f..0e8d3b2ef 100644 --- a/nativescript-angular/router/ns-router.ts +++ b/nativescript-angular/router/ns-router.ts @@ -5,7 +5,7 @@ import {NSLocationStrategy} from './ns-location-strategy'; import {ROUTER_PROVIDERS} from '@angular/router-deprecated'; import {LocationStrategy} from '@angular/common'; import {provide} from '@angular/core'; -import { CATEGORY } from "./common"; +export {routerTraceCategory} from "../trace"; export const NS_ROUTER_PROVIDERS: any[] = [ ROUTER_PROVIDERS, @@ -17,5 +17,3 @@ export const NS_ROUTER_DIRECTIVES: Type[] = [ NSRouterLink, PageRouterOutlet ]; - -export const routerTraceCategory = CATEGORY; diff --git a/nativescript-angular/router/page-router-outlet.ts b/nativescript-angular/router/page-router-outlet.ts index 3efdf75b1..cf8b002aa 100644 --- a/nativescript-angular/router/page-router-outlet.ts +++ b/nativescript-angular/router/page-router-outlet.ts @@ -19,7 +19,7 @@ import {topmost} from "ui/frame"; import {Page, NavigatedData} from "ui/page"; import {DEVICE} from "../platform-providers"; import {Device} from "platform"; -import {log} from "./common"; +import {routerLog} from "../trace"; import {NSLocationStrategy} from "./ns-location-strategy"; import {DetachedLoader} from "../common/detached-loader"; import {ViewUtil} from "../view-util"; @@ -106,7 +106,7 @@ export class PageRouterOutlet extends RouterOutlet { } private activateOnGoBack(nextInstruction: ComponentInstruction, previousInstruction: ComponentInstruction): Promise { - log("PageRouterOutlet.activate() - Back naviation, so load from cache: " + nextInstruction.componentType.name); + routerLog("PageRouterOutlet.activate() - Back naviation, so load from cache: " + nextInstruction.componentType.name); this.location.finishBackPageNavigation(); @@ -134,14 +134,14 @@ export class PageRouterOutlet extends RouterOutlet { ]; if (this.isInitalPage) { - log("PageRouterOutlet.activate() inital page - just load component: " + componentType.name); + routerLog("PageRouterOutlet.activate() inital page - just load component: " + componentType.name); this.isInitalPage = false; resultPromise = this.compiler.resolveComponent(componentType).then((componentFactory) => { const childInjector = ReflectiveInjector.resolveAndCreate(providersArray, this.containerRef.parentInjector); return this.containerRef.createComponent(componentFactory, this.containerRef.length, childInjector, null); }); } else { - log("PageRouterOutlet.activate() forward navigation - create detached loader in the loader container: " + componentType.name); + routerLog("PageRouterOutlet.activate() forward navigation - create detached loader in the loader container: " + componentType.name); const page = new Page(); providersArray.push(provide(Page, { useValue: page })); @@ -215,7 +215,7 @@ export class PageRouterOutlet extends RouterOutlet { } if (this.location.isPageNavigatingBack()) { - log("PageRouterOutlet.deactivate() while going back - should destroy: " + instruction.componentType.name) + routerLog("PageRouterOutlet.deactivate() while going back - should destroy: " + instruction.componentType.name) return next.then((_) => { const popedItem = this.refCache.pop(); const popedRef = popedItem.componentRef; @@ -275,7 +275,7 @@ export class PageRouterOutlet extends RouterOutlet { StringMapWrapper.equals(nextInstruction.params, this.currentInstruction.params)); } - log("PageRouterOutlet.routerCanReuse(): " + result); + routerLog("PageRouterOutlet.routerCanReuse(): " + result); return PromiseWrapper.resolve(result); } @@ -311,6 +311,6 @@ export class PageRouterOutlet extends RouterOutlet { } private log(method: string, nextInstruction: ComponentInstruction) { - log("PageRouterOutlet." + method + " isBack: " + this.location.isPageNavigatingBack() + " nextUrl: " + nextInstruction.urlPath); + routerLog("PageRouterOutlet." + method + " isBack: " + this.location.isPageNavigatingBack() + " nextUrl: " + nextInstruction.urlPath); } } diff --git a/nativescript-angular/trace.ts b/nativescript-angular/trace.ts new file mode 100644 index 000000000..bd2b695ab --- /dev/null +++ b/nativescript-angular/trace.ts @@ -0,0 +1,20 @@ +import {write, categories, messageType} from "trace"; + +export const rendererTraceCategory = "ns-renderer"; +export const routerTraceCategory = "ns-router"; + +export function rendererLog(msg): void { + write(msg, rendererTraceCategory); +} + +export function rendererError(message: string): void { + write(message, rendererTraceCategory, messageType.error); +} + +export function routerLog(message: string): void { + write(message, routerTraceCategory); +} + +export function styleError(message: string): void { + write(message, categories.Style, messageType.error); +} diff --git a/nativescript-angular/view-util.ts b/nativescript-angular/view-util.ts index 5f2fc9727..dd383b37c 100644 --- a/nativescript-angular/view-util.ts +++ b/nativescript-angular/view-util.ts @@ -9,24 +9,19 @@ import * as styleProperty from "ui/styling/style-property"; import {StyleProperty, getPropertyByName, withStyleProperty} from "ui/styling/style-property"; import {ValueSource} from "ui/core/dependency-observable"; import { ActionBar, ActionItem, NavigationButton } from "ui/action-bar"; -import trace = require("trace"); import {device, platformNames, Device} from "platform"; +import {rendererLog as traceLog, styleError} from "./trace"; const IOS_PREFX: string = "@ios:"; const ANDROID_PREFX: string = "@android:"; const whiteSpaceSplitter = /\s+/; -export const rendererTraceCategory = "ns-renderer"; export type ViewExtensions = ViewExtensions; export type NgView = NgView; export type NgLayoutBase = LayoutBase & ViewExtensions; export type NgContentView = ContentView & ViewExtensions; export type BeforeAttachAction = (view: View) => void; -export function traceLog(msg) { - trace.write(msg, rendererTraceCategory); -} - export function isView(view: any): view is NgView { return view instanceof View; } @@ -298,7 +293,7 @@ export class ViewUtil { try { view.style._setValue(property, value, ValueSource.Local); } catch (ex) { - trace.write("Error setting property: " + property.name + " view: " + view + " value: " + value + " " + ex, trace.categories.Style, trace.messageType.error); + styleError("Error setting property: " + property.name + " view: " + view + " value: " + value + " " + ex); } } diff --git a/ng-sample/app/app.ts b/ng-sample/app/app.ts index f43ef7267..3659877ae 100644 --- a/ng-sample/app/app.ts +++ b/ng-sample/app/app.ts @@ -7,12 +7,10 @@ // this import should be first in order to load some required settings (like globals and reflect-metadata) import { nativeScriptBootstrap } from "nativescript-angular/application"; -import { NS_ROUTER_PROVIDERS, routerTraceCategory } from "nativescript-angular/router"; -import { rendererTraceCategory } from "nativescript-angular/renderer"; +import { NS_ROUTER_PROVIDERS } from "nativescript-angular/router"; +import { rendererTraceCategory, routerTraceCategory } from "nativescript-angular/trace"; import trace = require("trace"); -//trace.setCategories(routerTraceCategory + ", " + rendererTraceCategory); -// trace.setCategories(rendererTraceCategory); trace.setCategories(routerTraceCategory); trace.enable(); @@ -41,4 +39,4 @@ import {LoginTest} from "./examples/navigation/login-test"; //nativeScriptBootstrap(ModalTest); //nativeScriptBootstrap(PlatfromDirectivesTest); //nativeScriptBootstrap(RouterOutletTest, [NS_ROUTER_PROVIDERS]); -nativeScriptBootstrap(LoginTest, [NS_ROUTER_PROVIDERS]); \ No newline at end of file +nativeScriptBootstrap(LoginTest, [NS_ROUTER_PROVIDERS]); diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 000000000..a6c22e275 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,37 @@ +RENDERER_DIR := ../nativescript-angular +RENDERER_SRC := $(shell find "$(RENDERER_DIR)" -iname '*.ts') +RENDERER_COMPILED := node_modules/nativescript-angular-latest.txt +RENDERER_LINKED := node_modules/renderer-linked.txt +SEMVER_CLEANED := node_modules/semver-cleaned.txt +APK := platforms/android/build/outputs/apk/ngtests-debug.apk +APP_SRC := $(shell find "app" -type f) + +$(APK): $(APP_SRC) $(RENDERER_COMPILED) + tns build android + @touch $@ + +appium-android: $(APK) $(SEMVER_CLEANED) + ./node_modules/.bin/nativescript-dev-appium android + +$(RENDERER_LINKED): + #npm link nativescript-angular + @mkdir -p node_modules + @touch $@ + +$(SEMVER_CLEANED): + tns install + find -L node_modules -iname '*.gz' -delete + @touch $@ + +clean: + @rm -rf node_modules platforms + +$(RENDERER_COMPILED): $(RENDERER_SRC) $(RENDERER_LINKED) + #cd "$(RENDERER_DIR)" && ./node_modules/.bin/tsc + npm install "$(RENDERER_DIR)" --production + @touch $@ + +run-android: $(RENDERER_COMPILED) $(SEMVER_CLEANED) + tns livesync android + +.PHONY: run-android clean appium-android diff --git a/tests/app/app.component.ts b/tests/app/app.component.ts index faae2a9cb..139a66991 100644 --- a/tests/app/app.component.ts +++ b/tests/app/app.component.ts @@ -1,11 +1,15 @@ import {Component} from "@angular/core"; +import {SinglePageMain} from "./single-page-main.component"; +import {MultiPageMain} from "./multi-page-main.component"; @Component({ selector: "my-app", + directives: [SinglePageMain, MultiPageMain], template: ` - - - + + `, }) export class AppComponent { diff --git a/tests/app/base.component.ts b/tests/app/base.component.ts new file mode 100644 index 000000000..28cc943ec --- /dev/null +++ b/tests/app/base.component.ts @@ -0,0 +1,23 @@ +import {ROUTER_DIRECTIVES, Router, OnActivate, OnDeactivate, CanReuse, OnReuse, + RouteParams, ComponentInstruction, RouteConfig } from '@angular/router-deprecated'; +import {Component, OpaqueToken} from "@angular/core"; +export const HOOKS_LOG = new OpaqueToken("Hooks log"); + +export class BaseComponent implements OnActivate, OnDeactivate { + protected name: string = ""; + + constructor(protected hooksLog: string[]) { + } + + routerOnActivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any { + this.log("activate", nextInstruction, prevInstruction); + } + + routerOnDeactivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any { + this.log("deactivate", nextInstruction, prevInstruction); + } + + private log(method: string, nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction) { + this.hooksLog.push(this.name + "." + method + " " + nextInstruction.urlPath + " " + (prevInstruction ? prevInstruction.urlPath : null)); + } +} diff --git a/tests/app/first.component.ts b/tests/app/first.component.ts new file mode 100644 index 000000000..f1c30a9a1 --- /dev/null +++ b/tests/app/first.component.ts @@ -0,0 +1,33 @@ +import {ROUTER_DIRECTIVES, Router, OnActivate, OnDeactivate, CanReuse, OnReuse, + RouteParams, RouteData, ComponentInstruction, RouteConfig } from '@angular/router-deprecated'; +import {Component, Inject} from "@angular/core"; +import {HOOKS_LOG, BaseComponent} from "./base.component"; + +@Component({ + selector: "first-comp", + template: ` + + + + + + + ` +}) +export class FirstComponent extends BaseComponent { + name = "first"; + + constructor(private router: Router, private routeData: RouteData, @Inject(HOOKS_LOG) hooksLog: string[]) { + super(hooksLog); + } + + ngOnInit() { + this.id = this.routeData.get('id'); + } + + public id: string = "" + + gotoSecond() { + this.router.navigateByUrl("/second"); + } +} diff --git a/tests/app/main.ts b/tests/app/main.ts index b44027695..80353f1f6 100644 --- a/tests/app/main.ts +++ b/tests/app/main.ts @@ -1,11 +1,56 @@ // this import should be first in order to load some required settings (like globals and reflect-metadata) -import {nativeScriptBootstrap} from "nativescript-angular/application"; +import {nativeScriptBootstrap, bootstrap} from "nativescript-angular/application"; import {AppComponent} from "./app.component"; import {GestureComponent} from "./snippets/gestures.component"; import {LayoutsComponent} from "./snippets/layouts.component"; import {IconFontComponent} from "./snippets/icon-font.component"; +import {NS_ROUTER_DIRECTIVES, NS_ROUTER_PROVIDERS} from "nativescript-angular/router/ns-router"; +import {APP_ROOT_VIEW} from "nativescript-angular/platform-providers"; +import {Page} from "ui/page"; +import {Label} from "ui/label"; +import {StackLayout} from "ui/layouts/stack-layout"; +import * as application from "application"; +//nativeScriptBootstrap(AppComponent, [NS_ROUTER_PROVIDERS]); +import {HOOKS_LOG} from "./base.component"; +import {MultiPageMain} from "./multi-page-main.component"; +import {SinglePageMain} from "./single-page-main.component"; +import {provide, OpaqueToken} from "@angular/core"; -nativeScriptBootstrap(AppComponent); +import { rendererTraceCategory, routerTraceCategory } from "nativescript-angular/trace"; + +import trace = require("trace"); +//trace.setCategories(rendererTraceCategory + "," + routerTraceCategory); +trace.enable(); + +//nativeScriptBootstrap(MultiPageMain, [NS_ROUTER_PROVIDERS]); // nativeScriptBootstrap(GestureComponent); // nativeScriptBootstrap(LayoutsComponent); // nativeScriptBootstrap(IconFontComponent); +application.start({ + create: (): Page => { + const page = new Page(); + const root = new StackLayout(); + page.content = root; + + let onLoadedHandler = function(args) { + page.off('loaded', onLoadedHandler); + //profiling.stop('application-start'); + console.log('Page loaded'); + + //profiling.start('ng-bootstrap'); + console.log('BOOTSTRAPPING TEST APPS...'); + //bootstrap(MultiPageMain, [NS_ROUTER_PROVIDERS]); + const rootViewProvider = provide(APP_ROOT_VIEW, { useValue: root }); + let singlePageHooksLog = [] + const singlePageHooksLogProvider = provide(HOOKS_LOG, { useValue: singlePageHooksLog }); + bootstrap(SinglePageMain, [rootViewProvider, singlePageHooksLogProvider, NS_ROUTER_PROVIDERS]); + let multiPageHooksLog = [] + const multiPageHooksLogProvider = provide(HOOKS_LOG, { useValue: multiPageHooksLog }); + bootstrap(MultiPageMain, [rootViewProvider, multiPageHooksLogProvider, NS_ROUTER_PROVIDERS]); + } + + page.on('loaded', onLoadedHandler); + + return page; + } +}); diff --git a/tests/app/multi-page-main.component.ts b/tests/app/multi-page-main.component.ts new file mode 100644 index 000000000..1d8e1bfa2 --- /dev/null +++ b/tests/app/multi-page-main.component.ts @@ -0,0 +1,28 @@ +import {ROUTER_DIRECTIVES, Router, OnActivate, OnDeactivate, CanReuse, OnReuse, + RouteParams, ComponentInstruction, RouteConfig } from '@angular/router-deprecated'; +import {NS_ROUTER_DIRECTIVES, NS_ROUTER_PROVIDERS} from "nativescript-angular/router/ns-router"; +import {Component, ElementRef} from "@angular/core"; +import {Location, LocationStrategy} from '@angular/common'; +import {FirstComponent} from "./first.component"; +import {SecondComponent} from "./second.component"; + +@Component({ + selector: "multi-page-main", + directives: [ROUTER_DIRECTIVES, NS_ROUTER_DIRECTIVES], + template: ` + + + ` + +}) +@RouteConfig([ + { path: '/first', name: 'First', component: FirstComponent, useAsDefault: true , data: {id: "multi-page"}}, + { path: '/second', name: 'Second', component: SecondComponent, data: {id: "multi-page"} } +]) +export class MultiPageMain { + constructor( + public elementRef: ElementRef, + public router: Router, + public location: LocationStrategy) { + } +} diff --git a/tests/app/second.component.ts b/tests/app/second.component.ts new file mode 100644 index 000000000..56a7e17db --- /dev/null +++ b/tests/app/second.component.ts @@ -0,0 +1,32 @@ +import {ROUTER_DIRECTIVES, Router, OnActivate, OnDeactivate, CanReuse, OnReuse, + RouteParams, RouteData, ComponentInstruction, RouteConfig } from '@angular/router-deprecated'; +import {Component, Inject} from "@angular/core"; +import {HOOKS_LOG, BaseComponent} from "./base.component"; + +@Component({ + selector: "second-comp", + template: ` + + + + + + + ` +}) +export class SecondComponent extends BaseComponent { + constructor(private router: Router, private routeData: RouteData, @Inject(HOOKS_LOG) hooksLog: string[]) { + super(hooksLog); + } + + ngOnInit() { + this.id = this.routeData.get('id'); + } + + public id: string = "" + name = "second"; + + gotoFirst() { + this.router.navigateByUrl("/first"); + } +} diff --git a/tests/app/single-page-main.component.ts b/tests/app/single-page-main.component.ts new file mode 100644 index 000000000..4fcf18357 --- /dev/null +++ b/tests/app/single-page-main.component.ts @@ -0,0 +1,27 @@ +import {ROUTER_DIRECTIVES, Router, OnActivate, OnDeactivate, CanReuse, OnReuse, + RouteParams, ComponentInstruction, RouteConfig } from '@angular/router-deprecated'; +import {Component, ElementRef} from "@angular/core"; +import {Location, LocationStrategy} from '@angular/common'; +import {FirstComponent} from "./first.component"; +import {SecondComponent} from "./second.component"; + +@Component({ + selector: "single-page-main", + directives: [ROUTER_DIRECTIVES], + template: ` + + + ` + +}) +@RouteConfig([ + { path: '/first', name: 'First', component: FirstComponent, useAsDefault: true , data: {id: "single-page"}}, + { path: '/second', name: 'Second', component: SecondComponent, data: {id: "single-page"} } +]) +export class SinglePageMain { + constructor( + public elementRef: ElementRef, + public router: Router, + public location: LocationStrategy) { + } +} diff --git a/tests/app/tests/router.ts b/tests/app/tests/router.ts deleted file mode 100644 index e63c8c7d4..000000000 --- a/tests/app/tests/router.ts +++ /dev/null @@ -1,250 +0,0 @@ -//make sure you import mocha-config before @angular/core -import {assert} from "./test-config"; -import { - Type, - Component, - ComponentRef, - DynamicComponentLoader, - ViewChild, - ElementRef, - provide, - ApplicationRef, - ChangeDetectorRef -} from "@angular/core"; - -import {ProxyViewContainer} from "ui/proxy-view-container"; -import {dumpView} from "./test-utils"; -import {bootstrapTestApp, destroyTestApp} from "./test-app"; - -import {ROUTER_DIRECTIVES, Router, OnActivate, OnDeactivate, CanReuse, OnReuse, - RouteParams, ComponentInstruction, RouteConfig } from '@angular/router-deprecated'; -import {Location, LocationStrategy} from '@angular/common'; -import {topmost, BackstackEntry} from "ui/frame"; -import {Page} from "ui/page"; -import {NS_ROUTER_DIRECTIVES, NS_ROUTER_PROVIDERS} from "nativescript-angular/router/ns-router"; - -@Component({ - template: `` -}) -export class LayoutWithLabel { - constructor(public elementRef: ElementRef) { } -} - - -const hooksLog = []; -class CompBase implements OnActivate, OnDeactivate { - protected name: string = ""; - - routerOnActivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any { - this.log("activate", nextInstruction, prevInstruction); - } - - routerOnDeactivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any { - this.log("deactivate", nextInstruction, prevInstruction); - } - - private log(method: string, nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction) { - hooksLog.push(this.name + "." + method + " " + nextInstruction.urlPath + " " + (prevInstruction ? prevInstruction.urlPath : null)); - } -} - -@Component({ - selector: "first-comp", - template: `` -}) -export class FirstComponent extends CompBase { - protected name = "first"; -} - -@Component({ - selector: "second-comp", - template: `` -}) -export class SecondComponent extends CompBase { - protected name = "second"; -} - -@Component({ - selector: "outlet-app", - directives: [ROUTER_DIRECTIVES], - template: `` - -}) -@RouteConfig([ - { path: '/first', name: 'First', component: FirstComponent, useAsDefault: true }, - { path: '/second', name: 'Second', component: SecondComponent } -]) -export class SimpleOutletCompnenet { - constructor( - public elementRef: ElementRef, - public router: Router, - public location: LocationStrategy) { - } -} - -@Component({ - selector: "page-outlet-app", - directives: [ROUTER_DIRECTIVES, NS_ROUTER_DIRECTIVES], - template: `` - -}) -@RouteConfig([ - { path: '/first', name: 'First', component: FirstComponent, useAsDefault: true }, - { path: '/second', name: 'Second', component: SecondComponent } -]) -export class PageOutletCompnenet { - constructor( - public elementRef: ElementRef, - public router: Router, - public location: LocationStrategy) { - } -} - -describe('router-outlet', () => { - let testApp: SimpleOutletCompnenet = null; - - beforeEach((done) => { - hooksLog.length = 0; - return bootstrapTestApp(SimpleOutletCompnenet, [NS_ROUTER_PROVIDERS]).then((app: SimpleOutletCompnenet) => { - testApp = app; - setTimeout(done, 0); - }); - }); - - afterEach(() => { - destroyTestApp(testApp) - }); - - - it("loads default path", () => { - assert.equal("(ROOT (ProxyViewContainer), (ProxyViewContainer (Label[text=First])))", dumpView(testApp.elementRef.nativeElement, true)); - }); - - it("navigates to other component", () => { - return testApp.router.navigateByUrl("/second").then(() => { - assert.equal("(ROOT (ProxyViewContainer), (ProxyViewContainer (Label[text=Second])))", dumpView(testApp.elementRef.nativeElement, true)); - }) - }); - - it("navigates to other component and then comes back", () => { - return testApp.router.navigateByUrl("/second").then(() => { - return testApp.router.navigateByUrl("/first"); - }).then(() => { - assert.equal("(ROOT (ProxyViewContainer), (ProxyViewContainer (Label[text=First])))", dumpView(testApp.elementRef.nativeElement, true)); - }) - }); - - it("hooks are fired when navigating", () => { - return testApp.router.navigateByUrl("/second").then(() => { - return testApp.router.navigateByUrl("/first"); - }).then(() => { - var expected = [ - "first.activate first null", - "first.deactivate second first", - "second.activate second first", - "second.deactivate first second", - "first.activate first second"]; - - assert.equal(hooksLog.join("|"), expected.join("|")); - }) - }); -}); - -describe.skip('page-router-outlet', () => { - let testApp: PageOutletCompnenet = null; - var initialBackstackLength: number; - var initalPage: Page; - - before((done) => { - // HACK: Wait for the navigations from the test runner app - // Remove the setTimeout when test runner start tests on page.navigatedTo - setTimeout(() => { - initialBackstackLength = topmost().backStack.length; - initalPage = topmost().currentPage; - done(); - }, 1000); - }) - - beforeEach((done) => { - hooksLog.length = 0; - - bootstrapTestApp(PageOutletCompnenet, [NS_ROUTER_PROVIDERS]).then((app: PageOutletCompnenet) => { - testApp = app; - setTimeout(done, 0); - }); - }); - - afterEach(() => { - destroyTestApp(testApp) - - // Ensure navigation to inital page - const backStack = topmost().backStack; - if (backStack.length > initialBackstackLength) { - return goBackToEntry(backStack[initialBackstackLength]); - } - else { - return true; - } - }); - - function goBackToEntry(entry: BackstackEntry): Promise { - var navPromise = getNavigatedPromise(entry.resolvedPage); - topmost().goBack(entry); - return navPromise; - } - - function getNavigatedPromise(page: Page): Promise { - return new Promise((resolve, reject) => { - var callback = () => { - page.off("navigatedTo", callback); - setTimeout(resolve, 0); - } - page.on("navigatedTo", callback) - }) - } - - it("loads default path", () => { - // App-Root app-component first-component - // | | | - var expected = "(ROOT (ProxyViewContainer), (ProxyViewContainer (Label[text=First])))"; - assert.equal(expected, dumpView(testApp.elementRef.nativeElement, true)); - }); - - it("navigates to other component", () => { - return testApp.router.navigateByUrl("/second") - .then(() => { - assert.equal("(ProxyViewContainer (Label[text=Second]))", dumpView(topmost().currentPage.content, true)); - }) - }); - - it("navigates to other component and then comes back", () => { - return testApp.router.navigateByUrl("/second") - .then(() => { - var navPromise = getNavigatedPromise(initalPage); - testApp.location.back(); - return navPromise; - }).then(() => { - assert.equal(topmost().currentPage, initalPage); - assert.equal("(ROOT (ProxyViewContainer), (ProxyViewContainer (Label[text=First])))", dumpView(testApp.elementRef.nativeElement, true)); - }) - }); - - - it("hooks are fired when navigating", () => { - return testApp.router.navigateByUrl("/second") - .then(() => { - var navPromise = getNavigatedPromise(initalPage); - testApp.location.back(); - return navPromise; - }).then(() => { - var expected = [ - "first.activate first null", - "first.deactivate second first", - "second.activate second first", - "second.deactivate first second", - "first.activate first second"]; - - assert.equal(hooksLog.join("|"), expected.join("|")); - }) - }); -}); diff --git a/tests/e2e-tests/multi-page-routing.js b/tests/e2e-tests/multi-page-routing.js new file mode 100644 index 000000000..c4e4b21b2 --- /dev/null +++ b/tests/e2e-tests/multi-page-routing.js @@ -0,0 +1,50 @@ +"use strict"; +var nsAppium = require("nativescript-dev-appium"); + +describe("multi page routing", function () { + this.timeout(120000); + var driver; + + before(function () { + driver = nsAppium.createDriver(); + }); + + after(function () { + return driver + .quit() + .finally(function () { + console.log("Driver quit successfully"); + }); + }); + + it("loads default path", function () { + return driver + .elementByAccessibilityId("first-multi-page") + .should.eventually.exist + .text().should.eventually.equal("First: multi-page") + }); + + it("navigates and returns", function () { + var expectedHookLog = [ + "first.activate first null", + "first.deactivate second first", + "second.activate second first", + "second.deactivate first second", + "first.activate first second"].join(","); + return driver + .elementByAccessibilityId("first-navigate-multi-page") + .should.eventually.exist + .tap() + .elementByAccessibilityId("second-multi-page") + .should.eventually.exist + .text().should.eventually.equal("Second: multi-page") + .elementByAccessibilityId("second-navigate-multi-page") + .should.eventually.exist + .tap() + .elementByAccessibilityId("first-multi-page") + .should.eventually.exist + .text().should.eventually.equal("First: multi-page") + .elementByAccessibilityId("hooks-log-multi-page") + .text().should.eventually.equal(expectedHookLog) + }); +}); diff --git a/tests/e2e-tests/single-page-routing.js b/tests/e2e-tests/single-page-routing.js new file mode 100644 index 000000000..d766866a5 --- /dev/null +++ b/tests/e2e-tests/single-page-routing.js @@ -0,0 +1,52 @@ +"use strict"; +var nsAppium = require("nativescript-dev-appium"); + +describe("single page routing", function () { + this.timeout(120000); + var driver; + + before(function () { + driver = nsAppium.createDriver(); + }); + + after(function () { + return driver + .quit() + .finally(function () { + console.log("Driver quit successfully"); + }); + }); + + it("loads default path", function () { + return driver + .elementByAccessibilityId("first-single-page") + .should.eventually.exist + .text().should.eventually.equal("First: single-page") + }); + + it("navigates, returns and fires hooks", function () { + var expectedHookLog = [ + "first.activate first null", + "first.deactivate second first", + "second.activate second first", + "second.deactivate first second", + "first.activate first second"].join(","); + + + return driver + .elementByAccessibilityId("first-navigate-single-page") + .should.eventually.exist + .tap() + .elementByAccessibilityId("second-single-page") + .should.eventually.exist + .text().should.eventually.equal("Second: single-page") + .elementByAccessibilityId("second-navigate-single-page") + .should.eventually.exist + .tap() + .elementByAccessibilityId("first-single-page") + .should.eventually.exist + .text().should.eventually.equal("First: single-page") + .elementByAccessibilityId("hooks-log-single-page") + .text().should.eventually.equal(expectedHookLog) + }); +}); diff --git a/tests/package.json b/tests/package.json index 725894f89..69d74aa73 100644 --- a/tests/package.json +++ b/tests/package.json @@ -1,6 +1,6 @@ { "nativescript": { - "id": "org.nativescript.helloworldng", + "id": "org.nativescript.ngtests", "tns-android": { "version": "2.0.0" }, @@ -8,11 +8,11 @@ "version": "2.0.0" } }, - "name": "nativescript-hello-world-ng", + "name": "ngtests", "main": "app.js", "version": "1.0.0", "author": "Telerik ", - "description": "Nativescript Angular Hello World template", + "description": "Angular tests", "license": "BSD", "keywords": [ "telerik", @@ -24,10 +24,6 @@ "appbuilder", "template" ], - "repository": { - "type": "git", - "url": "git://github.com/NativeScript/template-hello-world-ng" - }, "homepage": "http://nativescript.org", "dependencies": { "nativescript-unit-test-runner": "^0.3.3", @@ -54,6 +50,7 @@ "babel-types": "6.8.1", "babylon": "6.8.0", "chai": "^3.5.0", + "chai-as-promised": "^5.3.0", "filewalker": "0.1.2", "grunt-cli": "^1.2.0", "karma": "^0.13.19", @@ -63,11 +60,15 @@ "karma-nativescript-launcher": "^0.4.0", "lazy": "1.0.11", "mocha": "^2.4.5", + "nativescript-dev-appium": "^0.0.10", "nativescript-dev-typescript": "^0.3.1", "shelljs": "^0.5.3", - "typescript": "1.8.2" + "typescript": "^1.8.10", + "wd": "0.4.0" }, "scripts": { - "updateTests": "grunt updateTests" + "updateTests": "grunt updateTests", + "appium-android": "tns build android && nativescript-dev-appium android", + "appium-ios-simulator": "tns build ios && nativescript-dev-appium ios-simulator" } } \ No newline at end of file