Skip to content

Commit 85dc75e

Browse files
authored
fix-next: navigation events' workflow in modal dialog scenarios (NativeScript#5341)
1 parent b728a73 commit 85dc75e

File tree

12 files changed

+303
-61
lines changed

12 files changed

+303
-61
lines changed

tests/app/app/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,4 @@ else {
141141

142142
console.log(`TIME TO LOAD APP: ${time} ms`);
143143

144-
application.start({ moduleName: "app/mainPage" });
144+
application.run({ moduleName: "app/appRoot" });

tests/app/app/appRoot.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<Frame defaultPage="app/mainPage" />

tests/app/app/mainPage.ts

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { Page } from "tns-core-modules/ui/page";
22
import * as trace from "tns-core-modules/trace";
33
import * as tests from "../testRunner";
4-
import { Label } from "tns-core-modules/ui/label";
5-
import * as application from "tns-core-modules/application";
6-
import * as platform from "tns-core-modules/platform";
74

85
trace.enable();
96
trace.addCategories(trace.categories.Test + "," + trace.categories.Error);
@@ -18,46 +15,12 @@ trace.addCategories(trace.categories.Test + "," + trace.categories.Error);
1815
// trace.categories.VisualTreeEvents
1916
// ));
2017

21-
let page = new Page();
22-
page.id = "mainPage";
23-
24-
page.on(Page.navigatedToEvent, onNavigatedTo);
25-
2618
function runTests() {
2719
setTimeout(() => tests.runAll(''), 10);
2820
}
2921

30-
function onNavigatedTo(args) {
31-
let label = new Label();
32-
label.text = "Running non-UI tests...";
33-
page.content = label;
34-
args.object.off(Page.navigatedToEvent, onNavigatedTo);
35-
36-
// Request permission to write test-results.xml file for API >= 23
37-
// if (platform.isAndroid && parseInt(platform.device.sdkVersion) >= 23) {
38-
// let handler = (args: application.AndroidActivityRequestPermissionsEventData) => {
39-
// application.android.off(application.AndroidApplication.activityRequestPermissionsEvent, handler);
40-
// if (args.requestCode === 1234 && args.grantResults.length > 0 && args.grantResults[0] === android.content.pm.PackageManager.PERMISSION_GRANTED) {
41-
// runTests();
42-
// } else {
43-
// trace.write("Permission for write to external storage not granted!", trace.categories.Error, trace.messageType.error);
44-
// }
45-
// };
46-
47-
// application.android.on(application.AndroidApplication.activityRequestPermissionsEvent, handler);
48-
49-
// if ((<any>android.support.v4.content.ContextCompat).checkSelfPermission(application.android.currentContext, (<any>android).Manifest.permission.WRITE_EXTERNAL_STORAGE) !== android.content.pm.PackageManager.PERMISSION_GRANTED) {
50-
// (<any>android.support.v4.app.ActivityCompat).requestPermissions(application.android.currentContext, [(<any>android).Manifest.permission.WRITE_EXTERNAL_STORAGE], 1234);
51-
// } else {
52-
// runTests();
53-
// }
54-
// } else {
55-
// runTests();
56-
// }
22+
export function onNavigatedTo(args) {
23+
args.object.off(Page.loadedEvent, onNavigatedTo);
5724

5825
runTests();
5926
}
60-
61-
export function createPage() {
62-
return page;
63-
}

tests/app/app/mainPage.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<Page navigatedTo="onNavigatedTo">
2+
<Label text="Running non-UI tests..." />
3+
</Page>

tests/app/ui/page/page-tests-common.ts

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import * as helper from "../helper";
1919
import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout";
2020
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout";
2121
import { View, PercentLength, Observable, unsetValue, EventData, isIOS } from "tns-core-modules/ui/core/view";
22+
import { Frame } from "tns-core-modules/ui/frame";
2223
import { Label } from "tns-core-modules/ui/label";
2324
import { Color } from "tns-core-modules/color";
2425

@@ -538,6 +539,271 @@ export function test_WhenPageIsNavigatedToItCanShowAnotherPageAsModal() {
538539
masterPage.off(Page.navigatedToEvent, navigatedToEventHandler);
539540
}
540541

542+
export function test_WhenModalPageShownHostPageNavigationEventsShouldNotBeRaised() {
543+
let hostNavigatingToCount = 0;
544+
let hostNavigatedToCount = 0;
545+
let hostNavigatingFromCount = 0;
546+
let hostNavigatedFromCount = 0;
547+
548+
let ready = false;
549+
550+
const modalCloseCallback = function (returnValue: any) {
551+
ready = true;
552+
}
553+
554+
const hostNavigatingToEventHandler = function () {
555+
hostNavigatingToCount++;
556+
};
557+
558+
const hostNavigatedToEventHandler = function () {
559+
hostNavigatedToCount++;
560+
};
561+
562+
const hostNavigatingFromEventHandler = function () {
563+
hostNavigatingFromCount++;
564+
};
565+
566+
const hostNavigatedFromEventHandler = function () {
567+
hostNavigatedFromCount++;
568+
};
569+
570+
const hostNavigatedToEventHandler2 = function(args: NavigatedData) {
571+
const page = <Page>args.object;
572+
page.off(Page.navigatedToEvent, hostNavigatedToEventHandler2);
573+
574+
const basePath = "ui/page/";
575+
const entry: NavigationEntry = {
576+
moduleName: basePath + "modal-page"
577+
};
578+
579+
const modalPage = createViewFromEntry(entry) as Page;
580+
page.showModal(modalPage, {}, modalCloseCallback, false, false);
581+
}
582+
583+
const masterPageFactory = function (): Page {
584+
const masterPage = new Page();
585+
masterPage.id = "masterPage_test_WhenModalPageShownHostPageNavigationEventsShouldNotBeRaised";
586+
masterPage.on(Page.navigatingToEvent, hostNavigatingToEventHandler);
587+
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
588+
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler2);
589+
masterPage.on(Page.navigatingFromEvent, hostNavigatingFromEventHandler);
590+
masterPage.on(Page.navigatedFromEvent, hostNavigatedFromEventHandler);
591+
592+
const label = new Label();
593+
label.text = "Text";
594+
masterPage.content = label;
595+
return masterPage;
596+
};
597+
598+
helper.navigate(masterPageFactory);
599+
600+
TKUnit.waitUntilReady(() => ready);
601+
602+
// only raised by the initial navigation to the master page
603+
TKUnit.assertTrue(hostNavigatingToCount === 1);
604+
TKUnit.assertTrue(hostNavigatedToCount === 1);
605+
606+
TKUnit.assertTrue(hostNavigatingFromCount === 0);
607+
TKUnit.assertTrue(hostNavigatedFromCount === 0);
608+
}
609+
610+
export function test_WhenModalPageShownModalNavigationToEventsShouldBeRaised() {
611+
let modalNavigatingToCount = 0;
612+
let modalNavigatedToCount = 0;
613+
let modalNavigatingFromCount = 0;
614+
let modalNavigatedFromCount = 0;
615+
616+
let ready = false;
617+
618+
const modalCloseCallback = function (returnValue: any) {
619+
ready = true;
620+
}
621+
622+
const modalNavigatingToEventHandler = function () {
623+
modalNavigatingToCount++;
624+
};
625+
626+
const modalNavigatedToEventHandler = function (args: NavigatedData) {
627+
modalNavigatedToCount++;
628+
629+
(args.object as View).closeModal();
630+
};
631+
632+
const modalNavigatingFromEventHandler = function () {
633+
modalNavigatingFromCount++;
634+
};
635+
636+
const modalNavigatedFromEventHandler = function () {
637+
modalNavigatedFromCount++;
638+
};
639+
640+
const modalFrameShownModallyEventHandler = function(args) {
641+
const basePath = "ui/page/";
642+
const entry: NavigationEntry = {
643+
moduleName: basePath + "modal-page"
644+
};
645+
646+
const modalPage = createViewFromEntry(entry) as Page;
647+
modalPage.on(Page.navigatingToEvent, modalNavigatingToEventHandler);
648+
modalPage.on(Page.navigatedToEvent, modalNavigatedToEventHandler);
649+
modalPage.on(Page.navigatingFromEvent, modalNavigatingFromEventHandler);
650+
modalPage.on(Page.navigatedFromEvent, modalNavigatedFromEventHandler);
651+
652+
(args.object as Frame).navigate(() => modalPage);
653+
}
654+
655+
let modalFrame;
656+
657+
const hostNavigatedToEventHandler = function(args) {
658+
const page = <Page>args.object;
659+
page.off(Page.navigatedToEvent, hostNavigatedToEventHandler);
660+
661+
modalFrame = new Frame();
662+
modalFrame.on(Frame.shownModallyEvent, modalFrameShownModallyEventHandler);
663+
664+
page.showModal(modalFrame, {}, modalCloseCallback, false, false);
665+
}
666+
667+
const masterPageFactory = function (): Page {
668+
const masterPage = new Page();
669+
masterPage.id = "masterPage_test_WhenModalPageShownModalNavigationToEventsShouldBeRaised";
670+
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
671+
672+
const label = new Label();
673+
label.text = "Text";
674+
masterPage.content = label;
675+
return masterPage;
676+
};
677+
678+
helper.navigate(masterPageFactory);
679+
680+
TKUnit.waitUntilReady(() => ready && !modalFrame.isLoaded);
681+
682+
// only raised by the initial show modal navigation
683+
TKUnit.assertTrue(modalNavigatingToCount === 1);
684+
TKUnit.assertTrue(modalNavigatedToCount === 1);
685+
686+
TKUnit.assertTrue(modalNavigatingFromCount === 0);
687+
TKUnit.assertTrue(modalNavigatedFromCount === 0);
688+
}
689+
690+
export function test_WhenModalFrameShownModalEventsRaisedOnRootModalFrame() {
691+
let showingModallyCount = 0;
692+
let shownModallyCount = 0;
693+
694+
let ready = false;
695+
696+
const modalCloseCallback = function (returnValue: any) {
697+
ready = true;
698+
}
699+
700+
const modalFrameShowingModallyEventHandler = function(args: ShownModallyData) {
701+
showingModallyCount++;
702+
}
703+
704+
const modalFrameShownModallyEventHandler = function(args: ShownModallyData) {
705+
shownModallyCount++;
706+
707+
args.closeCallback("return value");
708+
}
709+
710+
let modalFrame;
711+
712+
const hostNavigatedToEventHandler = function(args) {
713+
const page = <Page>args.object;
714+
page.off(Page.navigatedToEvent, hostNavigatedToEventHandler);
715+
716+
const basePath = "ui/page/";
717+
const entry: NavigationEntry = {
718+
moduleName: basePath + "modal-page"
719+
};
720+
721+
const modalPage = createViewFromEntry(entry) as Page;
722+
723+
modalFrame = new Frame();
724+
modalFrame.on(Frame.showingModallyEvent, modalFrameShowingModallyEventHandler);
725+
modalFrame.on(Frame.shownModallyEvent, modalFrameShownModallyEventHandler);
726+
modalFrame.navigate(() => modalPage);
727+
728+
page.showModal(modalFrame, {}, modalCloseCallback, false, false);
729+
}
730+
731+
const masterPageFactory = function (): Page {
732+
const masterPage = new Page();
733+
masterPage.id = "masterPage_test_WhenModalFrameShownModalEventsRaisedOnRootModalFrame";
734+
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
735+
736+
const label = new Label();
737+
label.text = "Text";
738+
masterPage.content = label;
739+
return masterPage;
740+
};
741+
742+
helper.navigate(masterPageFactory);
743+
744+
TKUnit.waitUntilReady(() => ready && !modalFrame.isLoaded);
745+
746+
TKUnit.assertTrue(showingModallyCount === 1);
747+
TKUnit.assertTrue(shownModallyCount === 1);
748+
}
749+
750+
export function test_WhenModalPageShownShowModalEventsRaisedOnRootModalPage() {
751+
let showingModallyCount = 0;
752+
let shownModallyCount = 0;
753+
754+
let ready = false;
755+
756+
const modalCloseCallback = function (returnValue: any) {
757+
ready = true;
758+
}
759+
760+
const modalPageShowingModallyEventHandler = function(args: ShownModallyData) {
761+
showingModallyCount++;
762+
}
763+
764+
const modalPageShownModallyEventHandler = function(args: ShownModallyData) {
765+
shownModallyCount++;
766+
767+
setTimeout(() => {
768+
args.closeCallback("return value");
769+
}, 0);
770+
}
771+
772+
const hostNavigatedToEventHandler = function(args) {
773+
const page = <Page>args.object;
774+
page.off(Page.navigatedToEvent, hostNavigatedToEventHandler);
775+
776+
const basePath = "ui/page/";
777+
const entry: NavigationEntry = {
778+
moduleName: basePath + "modal-page"
779+
};
780+
781+
const modalPage = createViewFromEntry(entry) as Page;
782+
modalPage.on(Page.showingModallyEvent, modalPageShowingModallyEventHandler);
783+
modalPage.on(Page.shownModallyEvent, modalPageShownModallyEventHandler);
784+
785+
page.showModal(modalPage, {}, modalCloseCallback, false, false);
786+
}
787+
788+
const masterPageFactory = function (): Page {
789+
const masterPage = new Page();
790+
masterPage.id = "masterPage_test_WhenModalPageShownShowModalEventsRaisedOnRootModalPage";
791+
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
792+
793+
const label = new Label();
794+
label.text = "Text";
795+
masterPage.content = label;
796+
return masterPage;
797+
};
798+
799+
helper.navigate(masterPageFactory);
800+
801+
TKUnit.waitUntilReady(() => ready);
802+
803+
TKUnit.assertTrue(showingModallyCount === 1);
804+
TKUnit.assertTrue(shownModallyCount === 1);
805+
}
806+
541807
export function test_percent_width_and_height_support() {
542808
const testPage = new Page();
543809
testPage.id = "test_percent_width_and_height_support";

tests/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
"nativescript": {
77
"id": "org.nativescript.UnitTestApp",
88
"tns-ios": {
9-
"version": "3.2.0"
9+
"version": "3.4.1"
1010
},
1111
"tns-android": {
12-
"version": "3.2.0"
12+
"version": "3.4.1"
1313
}
1414
},
1515
"dependencies": {

tns-core-modules/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@
4040
"snapshot": {
4141
"android": {
4242
"tns-java-classes": {
43-
"modules": ["ui/frame/activity", "ui/frame/fragment"]
43+
"modules": [
44+
"ui/frame/activity",
45+
"ui/frame/fragment"
46+
]
4447
}
4548
}
4649
}

tns-core-modules/ui/core/view/view.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ export interface ShownModallyData extends EventData {
8585
* A View occupies a rectangular area on the screen and is responsible for drawing and layouting of all UI components within.
8686
*/
8787
export abstract class View extends ViewBase {
88+
/**
89+
* String value used when hooking to showingModally event.
90+
*/
91+
public static showingModallyEvent: string;
92+
93+
/**
94+
* String value used when hooking to shownModally event.
95+
*/
96+
public static shownModallyEvent: string;
97+
8898
/**
8999
* Gets the android-specific native instance that lies behind this proxy. Will be available if running on an Android platform.
90100
*/

0 commit comments

Comments
 (0)