diff --git a/tests/app/app/app.ts b/tests/app/app/app.ts
index d898ff4e6..6b35dfacf 100644
--- a/tests/app/app/app.ts
+++ b/tests/app/app/app.ts
@@ -141,4 +141,4 @@ else {
console.log(`TIME TO LOAD APP: ${time} ms`);
-application.start({ moduleName: "app/mainPage" });
+application.run({ moduleName: "app/appRoot" });
diff --git a/tests/app/app/appRoot.xml b/tests/app/app/appRoot.xml
new file mode 100644
index 000000000..b78a0e763
--- /dev/null
+++ b/tests/app/app/appRoot.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tests/app/app/mainPage.ts b/tests/app/app/mainPage.ts
index 049b79ac1..786b9320c 100644
--- a/tests/app/app/mainPage.ts
+++ b/tests/app/app/mainPage.ts
@@ -1,9 +1,6 @@
import { Page } from "tns-core-modules/ui/page";
import * as trace from "tns-core-modules/trace";
import * as tests from "../testRunner";
-import { Label } from "tns-core-modules/ui/label";
-import * as application from "tns-core-modules/application";
-import * as platform from "tns-core-modules/platform";
trace.enable();
trace.addCategories(trace.categories.Test + "," + trace.categories.Error);
@@ -18,46 +15,12 @@ trace.addCategories(trace.categories.Test + "," + trace.categories.Error);
// trace.categories.VisualTreeEvents
// ));
-let page = new Page();
-page.id = "mainPage";
-
-page.on(Page.navigatedToEvent, onNavigatedTo);
-
function runTests() {
setTimeout(() => tests.runAll(''), 10);
}
-function onNavigatedTo(args) {
- let label = new Label();
- label.text = "Running non-UI tests...";
- page.content = label;
- args.object.off(Page.navigatedToEvent, onNavigatedTo);
-
- // Request permission to write test-results.xml file for API >= 23
- // if (platform.isAndroid && parseInt(platform.device.sdkVersion) >= 23) {
- // let handler = (args: application.AndroidActivityRequestPermissionsEventData) => {
- // application.android.off(application.AndroidApplication.activityRequestPermissionsEvent, handler);
- // if (args.requestCode === 1234 && args.grantResults.length > 0 && args.grantResults[0] === android.content.pm.PackageManager.PERMISSION_GRANTED) {
- // runTests();
- // } else {
- // trace.write("Permission for write to external storage not granted!", trace.categories.Error, trace.messageType.error);
- // }
- // };
-
- // application.android.on(application.AndroidApplication.activityRequestPermissionsEvent, handler);
-
- // if ((android.support.v4.content.ContextCompat).checkSelfPermission(application.android.currentContext, (android).Manifest.permission.WRITE_EXTERNAL_STORAGE) !== android.content.pm.PackageManager.PERMISSION_GRANTED) {
- // (android.support.v4.app.ActivityCompat).requestPermissions(application.android.currentContext, [(android).Manifest.permission.WRITE_EXTERNAL_STORAGE], 1234);
- // } else {
- // runTests();
- // }
- // } else {
- // runTests();
- // }
+export function onNavigatedTo(args) {
+ args.object.off(Page.loadedEvent, onNavigatedTo);
runTests();
}
-
-export function createPage() {
- return page;
-}
\ No newline at end of file
diff --git a/tests/app/app/mainPage.xml b/tests/app/app/mainPage.xml
new file mode 100644
index 000000000..bee9a71d8
--- /dev/null
+++ b/tests/app/app/mainPage.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/tests/app/ui/page/page-tests-common.ts b/tests/app/ui/page/page-tests-common.ts
index 0a31f8bdd..4b8ee7569 100644
--- a/tests/app/ui/page/page-tests-common.ts
+++ b/tests/app/ui/page/page-tests-common.ts
@@ -19,6 +19,7 @@ import * as helper from "../helper";
import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout";
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout";
import { View, PercentLength, Observable, unsetValue, EventData, isIOS } from "tns-core-modules/ui/core/view";
+import { Frame } from "tns-core-modules/ui/frame";
import { Label } from "tns-core-modules/ui/label";
import { Color } from "tns-core-modules/color";
@@ -538,6 +539,271 @@ export function test_WhenPageIsNavigatedToItCanShowAnotherPageAsModal() {
masterPage.off(Page.navigatedToEvent, navigatedToEventHandler);
}
+export function test_WhenModalPageShownHostPageNavigationEventsShouldNotBeRaised() {
+ let hostNavigatingToCount = 0;
+ let hostNavigatedToCount = 0;
+ let hostNavigatingFromCount = 0;
+ let hostNavigatedFromCount = 0;
+
+ let ready = false;
+
+ const modalCloseCallback = function (returnValue: any) {
+ ready = true;
+ }
+
+ const hostNavigatingToEventHandler = function () {
+ hostNavigatingToCount++;
+ };
+
+ const hostNavigatedToEventHandler = function () {
+ hostNavigatedToCount++;
+ };
+
+ const hostNavigatingFromEventHandler = function () {
+ hostNavigatingFromCount++;
+ };
+
+ const hostNavigatedFromEventHandler = function () {
+ hostNavigatedFromCount++;
+ };
+
+ const hostNavigatedToEventHandler2 = function(args: NavigatedData) {
+ const page = args.object;
+ page.off(Page.navigatedToEvent, hostNavigatedToEventHandler2);
+
+ const basePath = "ui/page/";
+ const entry: NavigationEntry = {
+ moduleName: basePath + "modal-page"
+ };
+
+ const modalPage = createViewFromEntry(entry) as Page;
+ page.showModal(modalPage, {}, modalCloseCallback, false, false);
+ }
+
+ const masterPageFactory = function (): Page {
+ const masterPage = new Page();
+ masterPage.id = "masterPage_test_WhenModalPageShownHostPageNavigationEventsShouldNotBeRaised";
+ masterPage.on(Page.navigatingToEvent, hostNavigatingToEventHandler);
+ masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
+ masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler2);
+ masterPage.on(Page.navigatingFromEvent, hostNavigatingFromEventHandler);
+ masterPage.on(Page.navigatedFromEvent, hostNavigatedFromEventHandler);
+
+ const label = new Label();
+ label.text = "Text";
+ masterPage.content = label;
+ return masterPage;
+ };
+
+ helper.navigate(masterPageFactory);
+
+ TKUnit.waitUntilReady(() => ready);
+
+ // only raised by the initial navigation to the master page
+ TKUnit.assertTrue(hostNavigatingToCount === 1);
+ TKUnit.assertTrue(hostNavigatedToCount === 1);
+
+ TKUnit.assertTrue(hostNavigatingFromCount === 0);
+ TKUnit.assertTrue(hostNavigatedFromCount === 0);
+}
+
+export function test_WhenModalPageShownModalNavigationToEventsShouldBeRaised() {
+ let modalNavigatingToCount = 0;
+ let modalNavigatedToCount = 0;
+ let modalNavigatingFromCount = 0;
+ let modalNavigatedFromCount = 0;
+
+ let ready = false;
+
+ const modalCloseCallback = function (returnValue: any) {
+ ready = true;
+ }
+
+ const modalNavigatingToEventHandler = function () {
+ modalNavigatingToCount++;
+ };
+
+ const modalNavigatedToEventHandler = function (args: NavigatedData) {
+ modalNavigatedToCount++;
+
+ (args.object as View).closeModal();
+ };
+
+ const modalNavigatingFromEventHandler = function () {
+ modalNavigatingFromCount++;
+ };
+
+ const modalNavigatedFromEventHandler = function () {
+ modalNavigatedFromCount++;
+ };
+
+ const modalFrameShownModallyEventHandler = function(args) {
+ const basePath = "ui/page/";
+ const entry: NavigationEntry = {
+ moduleName: basePath + "modal-page"
+ };
+
+ const modalPage = createViewFromEntry(entry) as Page;
+ modalPage.on(Page.navigatingToEvent, modalNavigatingToEventHandler);
+ modalPage.on(Page.navigatedToEvent, modalNavigatedToEventHandler);
+ modalPage.on(Page.navigatingFromEvent, modalNavigatingFromEventHandler);
+ modalPage.on(Page.navigatedFromEvent, modalNavigatedFromEventHandler);
+
+ (args.object as Frame).navigate(() => modalPage);
+ }
+
+ let modalFrame;
+
+ const hostNavigatedToEventHandler = function(args) {
+ const page = args.object;
+ page.off(Page.navigatedToEvent, hostNavigatedToEventHandler);
+
+ modalFrame = new Frame();
+ modalFrame.on(Frame.shownModallyEvent, modalFrameShownModallyEventHandler);
+
+ page.showModal(modalFrame, {}, modalCloseCallback, false, false);
+ }
+
+ const masterPageFactory = function (): Page {
+ const masterPage = new Page();
+ masterPage.id = "masterPage_test_WhenModalPageShownModalNavigationToEventsShouldBeRaised";
+ masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
+
+ const label = new Label();
+ label.text = "Text";
+ masterPage.content = label;
+ return masterPage;
+ };
+
+ helper.navigate(masterPageFactory);
+
+ TKUnit.waitUntilReady(() => ready && !modalFrame.isLoaded);
+
+ // only raised by the initial show modal navigation
+ TKUnit.assertTrue(modalNavigatingToCount === 1);
+ TKUnit.assertTrue(modalNavigatedToCount === 1);
+
+ TKUnit.assertTrue(modalNavigatingFromCount === 0);
+ TKUnit.assertTrue(modalNavigatedFromCount === 0);
+}
+
+export function test_WhenModalFrameShownModalEventsRaisedOnRootModalFrame() {
+ let showingModallyCount = 0;
+ let shownModallyCount = 0;
+
+ let ready = false;
+
+ const modalCloseCallback = function (returnValue: any) {
+ ready = true;
+ }
+
+ const modalFrameShowingModallyEventHandler = function(args: ShownModallyData) {
+ showingModallyCount++;
+ }
+
+ const modalFrameShownModallyEventHandler = function(args: ShownModallyData) {
+ shownModallyCount++;
+
+ args.closeCallback("return value");
+ }
+
+ let modalFrame;
+
+ const hostNavigatedToEventHandler = function(args) {
+ const page = args.object;
+ page.off(Page.navigatedToEvent, hostNavigatedToEventHandler);
+
+ const basePath = "ui/page/";
+ const entry: NavigationEntry = {
+ moduleName: basePath + "modal-page"
+ };
+
+ const modalPage = createViewFromEntry(entry) as Page;
+
+ modalFrame = new Frame();
+ modalFrame.on(Frame.showingModallyEvent, modalFrameShowingModallyEventHandler);
+ modalFrame.on(Frame.shownModallyEvent, modalFrameShownModallyEventHandler);
+ modalFrame.navigate(() => modalPage);
+
+ page.showModal(modalFrame, {}, modalCloseCallback, false, false);
+ }
+
+ const masterPageFactory = function (): Page {
+ const masterPage = new Page();
+ masterPage.id = "masterPage_test_WhenModalFrameShownModalEventsRaisedOnRootModalFrame";
+ masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
+
+ const label = new Label();
+ label.text = "Text";
+ masterPage.content = label;
+ return masterPage;
+ };
+
+ helper.navigate(masterPageFactory);
+
+ TKUnit.waitUntilReady(() => ready && !modalFrame.isLoaded);
+
+ TKUnit.assertTrue(showingModallyCount === 1);
+ TKUnit.assertTrue(shownModallyCount === 1);
+}
+
+export function test_WhenModalPageShownShowModalEventsRaisedOnRootModalPage() {
+ let showingModallyCount = 0;
+ let shownModallyCount = 0;
+
+ let ready = false;
+
+ const modalCloseCallback = function (returnValue: any) {
+ ready = true;
+ }
+
+ const modalPageShowingModallyEventHandler = function(args: ShownModallyData) {
+ showingModallyCount++;
+ }
+
+ const modalPageShownModallyEventHandler = function(args: ShownModallyData) {
+ shownModallyCount++;
+
+ setTimeout(() => {
+ args.closeCallback("return value");
+ }, 0);
+ }
+
+ const hostNavigatedToEventHandler = function(args) {
+ const page = args.object;
+ page.off(Page.navigatedToEvent, hostNavigatedToEventHandler);
+
+ const basePath = "ui/page/";
+ const entry: NavigationEntry = {
+ moduleName: basePath + "modal-page"
+ };
+
+ const modalPage = createViewFromEntry(entry) as Page;
+ modalPage.on(Page.showingModallyEvent, modalPageShowingModallyEventHandler);
+ modalPage.on(Page.shownModallyEvent, modalPageShownModallyEventHandler);
+
+ page.showModal(modalPage, {}, modalCloseCallback, false, false);
+ }
+
+ const masterPageFactory = function (): Page {
+ const masterPage = new Page();
+ masterPage.id = "masterPage_test_WhenModalPageShownShowModalEventsRaisedOnRootModalPage";
+ masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
+
+ const label = new Label();
+ label.text = "Text";
+ masterPage.content = label;
+ return masterPage;
+ };
+
+ helper.navigate(masterPageFactory);
+
+ TKUnit.waitUntilReady(() => ready);
+
+ TKUnit.assertTrue(showingModallyCount === 1);
+ TKUnit.assertTrue(shownModallyCount === 1);
+}
+
export function test_percent_width_and_height_support() {
const testPage = new Page();
testPage.id = "test_percent_width_and_height_support";
diff --git a/tests/package.json b/tests/package.json
index dad1fda17..29a382188 100644
--- a/tests/package.json
+++ b/tests/package.json
@@ -6,10 +6,10 @@
"nativescript": {
"id": "org.nativescript.UnitTestApp",
"tns-ios": {
- "version": "3.2.0"
+ "version": "3.4.1"
},
"tns-android": {
- "version": "3.2.0"
+ "version": "3.4.1"
}
},
"dependencies": {
diff --git a/tns-core-modules/package.json b/tns-core-modules/package.json
index 9675da85b..1aa48fdae 100644
--- a/tns-core-modules/package.json
+++ b/tns-core-modules/package.json
@@ -40,7 +40,10 @@
"snapshot": {
"android": {
"tns-java-classes": {
- "modules": ["ui/frame/activity", "ui/frame/fragment"]
+ "modules": [
+ "ui/frame/activity",
+ "ui/frame/fragment"
+ ]
}
}
}
diff --git a/tns-core-modules/ui/core/view/view.d.ts b/tns-core-modules/ui/core/view/view.d.ts
index e2740068b..7ab7f6209 100644
--- a/tns-core-modules/ui/core/view/view.d.ts
+++ b/tns-core-modules/ui/core/view/view.d.ts
@@ -85,6 +85,16 @@ export interface ShownModallyData extends EventData {
* A View occupies a rectangular area on the screen and is responsible for drawing and layouting of all UI components within.
*/
export abstract class View extends ViewBase {
+ /**
+ * String value used when hooking to showingModally event.
+ */
+ public static showingModallyEvent: string;
+
+ /**
+ * String value used when hooking to shownModally event.
+ */
+ public static shownModallyEvent: string;
+
/**
* Gets the android-specific native instance that lies behind this proxy. Will be available if running on an Android platform.
*/
diff --git a/tns-core-modules/ui/frame/frame-common.ts b/tns-core-modules/ui/frame/frame-common.ts
index f111b08b5..3e43cfb17 100644
--- a/tns-core-modules/ui/frame/frame-common.ts
+++ b/tns-core-modules/ui/frame/frame-common.ts
@@ -58,9 +58,18 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
@profile
public onLoaded() {
super.onLoaded();
+
+ this._pushInFrameStack();
this._processNextNavigationEntry();
}
+ @profile
+ public onUnloaded() {
+ super.onUnloaded();
+
+ this._popFromFrameStack();
+ }
+
public canGoBack(): boolean {
let backstack = this._backStack.length;
let previousForwardNotInBackstack = false;
@@ -183,8 +192,6 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
// app.on(app.orientationChangedEvent, (data) => this._onOrientationChanged());
// }
- this._pushInFrameStack();
-
const backstackEntry: BackstackEntry = {
entry: entry,
resolvedPage: page,
diff --git a/tns-core-modules/ui/page/page.d.ts b/tns-core-modules/ui/page/page.d.ts
index a75c13268..a9ace3677 100644
--- a/tns-core-modules/ui/page/page.d.ts
+++ b/tns-core-modules/ui/page/page.d.ts
@@ -39,16 +39,6 @@ export module knownCollections {
* Represents a logical unit for navigation (inside Frame).
*/
export class Page extends ContentView {
- /**
- * String value used when hooking to showingModally event.
- */
- public static showingModallyEvent: string;
-
- /**
- * String value used when hooking to shownModally event.
- */
- public static shownModallyEvent: string;
-
/**
* String value used when hooking to navigatingTo event.
*/
diff --git a/tns-core-modules/ui/page/page.ios.ts b/tns-core-modules/ui/page/page.ios.ts
index 00aa75415..bd3e42c25 100644
--- a/tns-core-modules/ui/page/page.ios.ts
+++ b/tns-core-modules/ui/page/page.ios.ts
@@ -180,10 +180,11 @@ class UIViewControllerImpl extends UIViewController {
}
const frame = owner.frame;
- // Skip navigation events if we are hiding because we are about to show modal page
+ // Skip navigation events if we are hiding because we are about to show a modal page,
+ // or because we are closing a modal page,
// or because we are in tab and another controller is selected.
const tab = this.tabBarController;
- if (!owner._presentedViewController && frame && frame.currentPage === owner) {
+ if (!owner._presentedViewController && !this.presentingViewController && frame && frame.currentPage === owner) {
const willSelectViewController = tab && (tab)._willSelectViewController;
if (!willSelectViewController
|| willSelectViewController === tab.selectedViewController) {
diff --git a/tns-platform-declarations/package.json b/tns-platform-declarations/package.json
index 7fe6b1b98..3e0800e08 100644
--- a/tns-platform-declarations/package.json
+++ b/tns-platform-declarations/package.json
@@ -1,13 +1,11 @@
{
"name": "tns-platform-declarations",
"version": "4.0.0",
- "description":
- "Platform-specific TypeScript declarations for NativeScript for accessing native objects",
+ "description": "Platform-specific TypeScript declarations for NativeScript for accessing native objects",
"main": "",
"scripts": {
"test": "tsc",
- "package-tag":
- "npm version $npm_package_version-$PACKAGE_VERSION --no-git-tag-version"
+ "package-tag": "npm version $npm_package_version-$PACKAGE_VERSION --no-git-tag-version"
},
"repository": {
"type": "git",