Skip to content

Commit 389f5b7

Browse files
authored
refactor: ActionBar directive and patching of Views in renderer (#979)
refactor(renderer): invoke removeFromQueue for every element refactor(action-bar): insert ActionItems at correct positions ActionBar's insertChild method is now passed a next view argument. When the view to insert is an ActionItem, next is used to find the correct position to insert the new item. refactor(renderer): patch every View with ViewExtensions When a View is passed through the renderer on insert/remove it's patched with ViewExtensions for its class. That is done for parent views and for child views. fixes #689, fixes #978
1 parent a262281 commit 389f5b7

11 files changed

+419
-80
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Component } from "@angular/core";
2+
3+
@Component({
4+
template: `
5+
<ActionBar title="Action Bar Dynamic Items">
6+
<NavigationButton
7+
*ngIf="showNavigationButton"
8+
android.systemIcon="ic_menu_back"
9+
></NavigationButton>
10+
11+
<ActionItem text="one" *ngIf="show1"></ActionItem>
12+
<ActionItem text="two" *ngIf="show2"></ActionItem>
13+
</ActionBar>
14+
15+
<StackLayout>
16+
<Button text="toggle nav" (tap)="showNavigationButton = !showNavigationButton"></Button>
17+
<Button text="toggle 1" (tap)="show1 = !show1"></Button>
18+
<Button text="toggle 2" (tap)="show2 = !show2"></Button>
19+
</StackLayout>
20+
`
21+
})
22+
export class ActionBarDynamicItemsComponent {
23+
public showNavigationButton = true;
24+
public show1 = true;
25+
public show2 = true;
26+
}
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Component } from "@angular/core";
2+
3+
@Component({
4+
template: `
5+
<ActionBarExtension>
6+
<ActionItem (tap)="show = !show" text="toggle">
7+
</ActionItem>
8+
9+
<ActionItem *ngIf="show" text="conditional">
10+
</ActionItem>
11+
</ActionBarExtension>
12+
`
13+
})
14+
export class ActionBarExtensionComponent {
15+
public show = true;
16+
}

Diff for: e2e/renderer/app/app-routing.module.ts

+14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
22
import { NativeScriptRouterModule } from "nativescript-angular/router";
33

4+
import { ActionBarDynamicItemsComponent } from "./action-bar/action-bar-dynamic-items.component";
5+
import { ActionBarExtensionComponent } from "./action-bar/action-bar-extension.component";
6+
47
import { ListComponent } from "./list.component";
58
import { NgForComponent } from "./ngfor.component";
69
import { NgForOfComponent } from "./ngforof.component";
@@ -17,6 +20,14 @@ export const routes = [
1720
redirectTo: "/list",
1821
pathMatch: "full"
1922
},
23+
{
24+
path: "action-bar-dynamic",
25+
component: ActionBarDynamicItemsComponent,
26+
},
27+
{
28+
path: "action-bar-extension",
29+
component: ActionBarExtensionComponent,
30+
},
2031
{
2132
path: "list",
2233
component: ListComponent,
@@ -56,6 +67,9 @@ export const routes = [
5667
];
5768

5869
export const navigatableComponents = [
70+
ActionBarDynamicItemsComponent,
71+
ActionBarExtensionComponent,
72+
5973
ListComponent,
6074
NgForComponent,
6175
NgForOfComponent,

Diff for: e2e/renderer/app/content-view.component.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Component } from "@angular/core";
22

33
@Component({
4-
selector: "my-app",
54
template: `
65
<ActionBar title="Content View">
76
<ActionItem (tap)="toggle()">

Diff for: e2e/renderer/app/list.component.ts

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Component } from "@angular/core";
33
@Component({
44
template: `
55
<FlexboxLayout flexDirection="column">
6+
<Button text="ActionBar dynamic" [nsRouterLink]="['/action-bar-dynamic']"></Button>
7+
<Button text="ActionBarExtension" [nsRouterLink]="['/action-bar-extension']"></Button>
68
<Button text="NgFor" [nsRouterLink]="['/ngfor']"></Button>
79
<Button text="NgForOf" [nsRouterLink]="['/ngforof']"></Button>
810
<Button text="NgIf no layout" [nsRouterLink]="['/ngif-no-layout']"></Button>

Diff for: e2e/renderer/e2e/action-bar.e2e-spec.ts

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import {
2+
AppiumDriver,
3+
createDriver,
4+
SearchOptions,
5+
elementHelper,
6+
} from "nativescript-dev-appium";
7+
8+
import { isOnTheLeft } from "./helpers/location";
9+
import { DriverWrapper, ExtendedUIElement } from "./helpers/appium-elements";
10+
11+
describe("Action Bar scenario", () => {
12+
let driver: AppiumDriver;
13+
let driverWrapper: DriverWrapper;
14+
15+
describe("dynamically add/remove ActionItems", async () => {
16+
let firstActionItem: ExtendedUIElement;
17+
let secondActionItem: ExtendedUIElement;
18+
let toggleFirstButton: ExtendedUIElement;
19+
let toggleSecondButton: ExtendedUIElement;
20+
21+
before(async () => {
22+
driver = await createDriver();
23+
driverWrapper = new DriverWrapper(driver);
24+
});
25+
26+
after(async () => {
27+
await driver.quit();
28+
console.log("Driver quits!");
29+
});
30+
31+
it("should navigate to page", async () => {
32+
const navigationButton =
33+
await driverWrapper.findElementByText("ActionBar dynamic", SearchOptions.exact);
34+
await navigationButton.click();
35+
36+
const actionBar =
37+
await driverWrapper.findElementByText("Action Bar Dynamic Items", SearchOptions.exact);
38+
});
39+
40+
it("should find elements", async () => {
41+
firstActionItem = await driverWrapper.findElementByText("one");
42+
secondActionItem = await driverWrapper.findElementByText("two");
43+
44+
toggleFirstButton = await driverWrapper.findElementByText("toggle 1");
45+
toggleSecondButton = await driverWrapper.findElementByText("toggle 2");
46+
});
47+
48+
it("should initially render the action items in the correct order", async () => {
49+
await checkOrderIsCorrect();
50+
});
51+
52+
it("should detach first element when its condition is false", done => {
53+
(async () => {
54+
await toggleFirst();
55+
56+
try {
57+
await driverWrapper.findElementByText("one", SearchOptions.exact);
58+
} catch (e) {
59+
done();
60+
}
61+
})();
62+
});
63+
64+
it("should attach first element in the correct position", async () => {
65+
await toggleFirst();
66+
await checkOrderIsCorrect();
67+
});
68+
69+
it("should detach second element when its condition is false", done => {
70+
(async () => {
71+
await toggleSecond();
72+
73+
try {
74+
await driverWrapper.findElementByText("two", SearchOptions.exact);
75+
} catch (e) {
76+
done();
77+
}
78+
})();
79+
});
80+
81+
it("should attach second element in the correct position", async () => {
82+
await toggleSecond();
83+
await checkOrderIsCorrect();
84+
});
85+
86+
it("should detach and then reattach both at correct places", async () => {
87+
await toggleFirst();
88+
await toggleSecond();
89+
90+
await toggleFirst();
91+
await toggleSecond();
92+
93+
await checkOrderIsCorrect();
94+
});
95+
96+
const checkOrderIsCorrect = async () => {
97+
await isOnTheLeft(firstActionItem, secondActionItem);
98+
};
99+
100+
const toggleFirst = async () => {
101+
toggleFirstButton = await toggleFirstButton.refetch();
102+
await toggleFirstButton.click();
103+
};
104+
105+
const toggleSecond = async () => {
106+
toggleSecondButton = await toggleSecondButton.refetch();
107+
await toggleSecondButton.click();
108+
};
109+
110+
});
111+
112+
describe("Action Bar extension with dynamic ActionItem", async () => {
113+
let toggleButton: ExtendedUIElement;
114+
let conditional: ExtendedUIElement;
115+
116+
before(async () => {
117+
driver = await createDriver();
118+
driverWrapper = new DriverWrapper(driver);
119+
});
120+
121+
after(async () => {
122+
await driver.quit();
123+
console.log("Driver quits!");
124+
});
125+
126+
it("should navigate to page", async () => {
127+
const navigationButton =
128+
await driverWrapper.findElementByText("ActionBarExtension", SearchOptions.exact);
129+
await navigationButton.click();
130+
});
131+
132+
it("should find elements", async () => {
133+
toggleButton = await driverWrapper.findElementByText("toggle");
134+
conditional = await driverWrapper.findElementByText("conditional");
135+
});
136+
137+
it("should detach conditional action item when its condition is false", done => {
138+
(async () => {
139+
await toggle();
140+
141+
try {
142+
await driverWrapper.findElementByText("conditional", SearchOptions.exact);
143+
} catch (e) {
144+
done();
145+
}
146+
})();
147+
});
148+
149+
it("should reattach conditional action item at correct place", async () => {
150+
await toggle();
151+
await checkOrderIsCorrect();
152+
});
153+
154+
const checkOrderIsCorrect = async () => {
155+
await isOnTheLeft(toggleButton, conditional);
156+
};
157+
158+
const toggle = async () => {
159+
toggleButton = await toggleButton.refetch();
160+
await toggleButton.click();
161+
};
162+
});
163+
});

Diff for: e2e/renderer/e2e/helpers/appium-elements.ts

+21
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,25 @@ export class DriverWrapper {
3838

3939
return result;
4040
}
41+
42+
@refetchable()
43+
async findElementByXPath(...args: any[]): Promise<ExtendedUIElement> {
44+
const result = await (<any>this.driver).findElementByXPath(...args);
45+
46+
return result;
47+
}
48+
49+
@refetchable()
50+
async findElementsByXPath(...args: any[]): Promise<ExtendedUIElement[]> {
51+
const result = await (<any>this.driver).findElementsByXPath(...args);
52+
53+
return result || [];
54+
}
55+
56+
@refetchable()
57+
async findElementsByClassName(...args: any[]): Promise<ExtendedUIElement[]> {
58+
const result = await (<any>this.driver).findElementsByClassName(...args);
59+
60+
return result || [];
61+
}
4162
}

Diff for: e2e/renderer/e2e/helpers/location.ts

+11
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,14 @@ export const isAbove = async (first: ExtendedUIElement, second: ExtendedUIElemen
1111

1212
assert.isTrue(firstY < secondY);
1313
}
14+
15+
export const isOnTheLeft = async (first: ExtendedUIElement, second: ExtendedUIElement) => {
16+
first = await first.refetch();
17+
second = await second.refetch();
18+
19+
const { x: firstX } = await first.location();
20+
const { x: secondX } = await second.location();
21+
22+
assert.isTrue(firstX < secondX);
23+
}
24+

0 commit comments

Comments
 (0)