Skip to content

Commit c3d5348

Browse files
authored
Merge pull request #152 from synonymdev/feat/system-widgets-foundation
Feat/system widgets foundation
2 parents 6be4e0c + c3044a9 commit c3d5348

5 files changed

Lines changed: 288 additions & 117 deletions

File tree

test/helpers/actions.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,23 +1423,6 @@ export async function verifyAmountToSend(amount: number) {
14231423
await expectTextWithin('SendNumberField', formatSats(amount));
14241424
}
14251425

1426-
export async function deleteAllDefaultWidgets() {
1427-
await swipeFullScreen('up');
1428-
await swipeFullScreen('up');
1429-
await tap('WidgetsEdit');
1430-
for (const w of ['Bitcoin Price', 'Bitcoin Blocks', 'Bitkit Suggestions']) {
1431-
tap(w + '_WidgetActionDelete');
1432-
await elementByText('Yes, Delete').waitForDisplayed();
1433-
await elementByText('Yes, Delete').click();
1434-
await elementById(w).waitForDisplayed({ reverse: true, timeout: 5000 });
1435-
await sleep(1000);
1436-
}
1437-
await tap('WidgetsEdit');
1438-
await elementById('PriceWidget').waitForDisplayed({ reverse: true });
1439-
await elementById('SuggestionsWidget').waitForDisplayed({ reverse: true });
1440-
await elementById('BlocksWidget').waitForDisplayed({ reverse: true });
1441-
}
1442-
14431426
export async function attemptRefreshOnHomeScreen() {
14441427
await swipeFullScreen('down');
14451428
await sleep(2000); // wait for the app to settle

test/helpers/navigation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export async function openSupport() {
2727
* Closes the drawer and navigates back to the Wallet home screen.
2828
*/
2929
export async function doNavigationClose() {
30+
await sleep(500);
3031
await tap('HeaderMenu');
3132
await tap('DrawerWallet');
3233
await sleep(500);

test/helpers/widgets.ts

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import { elementById, elementByText, sleep, swipeFullScreen, tap } from './actions';
2+
3+
export type WidgetId =
4+
| 'price'
5+
| 'blocks'
6+
| 'news'
7+
| 'facts'
8+
| 'weather'
9+
| 'suggestions'
10+
| 'calculator';
11+
12+
type WidgetMetadata = {
13+
listItemId: string;
14+
actionName: string;
15+
homeId?: () => string | undefined;
16+
hasSettings: () => boolean;
17+
};
18+
19+
const WIDGETS: Record<WidgetId, WidgetMetadata> = {
20+
price: {
21+
listItemId: 'WidgetListItem-price',
22+
actionName: 'Bitcoin Price',
23+
homeId: () => 'PriceWidget',
24+
hasSettings: () => true,
25+
},
26+
blocks: {
27+
listItemId: 'WidgetListItem-blocks',
28+
actionName: 'Bitcoin Blocks',
29+
homeId: () => 'BlocksWidget',
30+
hasSettings: () => true,
31+
},
32+
news: {
33+
listItemId: 'WidgetListItem-news',
34+
actionName: 'Bitcoin Headlines',
35+
homeId: () => 'NewsWidget',
36+
hasSettings: () => true,
37+
},
38+
facts: {
39+
listItemId: 'WidgetListItem-facts',
40+
actionName: 'Bitcoin Facts',
41+
homeId: () => (driver.isIOS ? 'FactsWidget' : undefined),
42+
hasSettings: () => driver.isIOS,
43+
},
44+
weather: {
45+
listItemId: 'WidgetListItem-weather',
46+
actionName: 'Bitcoin Weather',
47+
homeId: () => (driver.isIOS ? 'WeatherWidget' : undefined),
48+
hasSettings: () => true,
49+
},
50+
suggestions: {
51+
listItemId: 'WidgetListItem-suggestions',
52+
actionName: 'Bitkit Suggestions',
53+
homeId: () => 'SuggestionsWidget',
54+
hasSettings: () => false,
55+
},
56+
calculator: {
57+
listItemId: 'WidgetListItem-calculator',
58+
actionName: 'Calculator',
59+
homeId: () => 'CalculatorWidget',
60+
hasSettings: () => false,
61+
},
62+
};
63+
64+
const DEFAULT_WIDGETS: WidgetId[] = ['price', 'blocks', 'suggestions'];
65+
66+
function widgetMetadata(widget: WidgetId): WidgetMetadata {
67+
return WIDGETS[widget];
68+
}
69+
70+
function widgetActionId(widget: WidgetId, action: 'Delete' | 'Edit' | 'Drag') {
71+
return `${widgetMetadata(widget).actionName}_WidgetAction${action}`;
72+
}
73+
74+
async function tapIfDisplayed(testId: string, timeout = 2_000): Promise<boolean> {
75+
const element = await elementById(testId);
76+
try {
77+
await element.waitForDisplayed({ timeout });
78+
await element.click();
79+
await sleep(300);
80+
return true;
81+
} catch {
82+
return false;
83+
}
84+
}
85+
86+
async function tapWidgetListItem(widget: WidgetId) {
87+
const { listItemId } = widgetMetadata(widget);
88+
if (await tapIfDisplayed(listItemId)) {
89+
return;
90+
}
91+
await swipeFullScreen('up');
92+
await tap(listItemId);
93+
}
94+
95+
export async function scrollHomeToWidgets() {
96+
await swipeFullScreen('up');
97+
await swipeFullScreen('up');
98+
await sleep(500);
99+
}
100+
101+
export async function openWidgetsFeed() {
102+
await scrollHomeToWidgets();
103+
await tap('WidgetsAdd');
104+
await tapIfDisplayed('WidgetsOnboarding-button');
105+
}
106+
107+
export async function openWidgetPreview(widget: WidgetId) {
108+
await openWidgetsFeed();
109+
await tapWidgetListItem(widget);
110+
}
111+
112+
export async function addWidget(widget: WidgetId) {
113+
await openWidgetPreview(widget);
114+
await tap('WidgetSave');
115+
await elementById('WidgetsAdd').waitForDisplayed({ timeout: 15_000 });
116+
}
117+
118+
export async function openWidgetSettings(widget: WidgetId) {
119+
if (!widgetMetadata(widget).hasSettings()) {
120+
throw new Error(`Widget '${widget}' does not have editable settings on this platform`);
121+
}
122+
await tap('WidgetEdit');
123+
await elementById('WidgetEditPreview').waitForDisplayed();
124+
}
125+
126+
export async function openSavedWidgetPreview(widget: WidgetId) {
127+
await scrollHomeToWidgets();
128+
await tap('WidgetsEdit');
129+
await tap(widgetActionId(widget, 'Edit'));
130+
await elementById('WidgetSave').waitForDisplayed();
131+
}
132+
133+
export async function expectWidgetPresent(
134+
widget: WidgetId,
135+
present = true,
136+
{ timeout = 8_000 }: { timeout?: number } = {}
137+
) {
138+
const homeId = widgetMetadata(widget).homeId?.();
139+
if (!homeId) {
140+
await expectWidgetSavedInEditList(widget, present, { timeout });
141+
return;
142+
}
143+
await elementById(homeId).waitForDisplayed({
144+
reverse: !present,
145+
timeout,
146+
interval: 250,
147+
});
148+
}
149+
150+
export async function expectWidgetSavedInEditList(
151+
widget: WidgetId,
152+
present = true,
153+
{ timeout = 8_000 }: { timeout?: number } = {}
154+
) {
155+
await scrollHomeToWidgets();
156+
await tap('WidgetsEdit');
157+
await elementById(widgetActionId(widget, 'Delete')).waitForDisplayed({
158+
reverse: !present,
159+
timeout,
160+
interval: 250,
161+
});
162+
await tap('WidgetsEdit');
163+
}
164+
165+
export async function deleteWidget(widget: WidgetId) {
166+
await scrollHomeToWidgets();
167+
await tap('WidgetsEdit');
168+
await tap(widgetActionId(widget, 'Delete'));
169+
await elementByText('Yes, Delete').waitForDisplayed();
170+
await elementByText('Yes, Delete').click();
171+
await elementById(widgetActionId(widget, 'Delete')).waitForDisplayed({
172+
reverse: true,
173+
timeout: 8_000,
174+
interval: 250,
175+
});
176+
await tap('WidgetsEdit');
177+
await sleep(500);
178+
}
179+
180+
export async function deleteWidgets(widgets: WidgetId[]) {
181+
await scrollHomeToWidgets();
182+
await tap('WidgetsEdit');
183+
for (const widget of widgets) {
184+
if (!(await tapIfDisplayed(widgetActionId(widget, 'Delete')))) {
185+
continue;
186+
}
187+
await elementByText('Yes, Delete').waitForDisplayed();
188+
await elementByText('Yes, Delete').click();
189+
await elementById(widgetActionId(widget, 'Delete')).waitForDisplayed({
190+
reverse: true,
191+
timeout: 8_000,
192+
interval: 250,
193+
});
194+
await sleep(500);
195+
}
196+
await tap('WidgetsEdit');
197+
}
198+
199+
export async function deleteAllDefaultWidgets() {
200+
await deleteWidgets(DEFAULT_WIDGETS);
201+
for (const widget of DEFAULT_WIDGETS) {
202+
await expectWidgetPresent(widget, false);
203+
}
204+
}

test/specs/backup.e2e.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { reinstallApp } from '../helpers/setup';
33
import {
44
completeOnboarding,
55
confirmInputOnKeyboard,
6-
deleteAllDefaultWidgets,
76
doNavigationClose,
87
elementById,
98
elementByIdWithin,
@@ -20,6 +19,7 @@ import {
2019
import { ciIt } from '../helpers/suite';
2120
import { ensureLocalFunds } from '../helpers/regtest';
2221
import { openSettings } from '../helpers/navigation';
22+
import { deleteAllDefaultWidgets } from '../helpers/widgets';
2323

2424
describe('@backup - Backup', () => {
2525
let electrum: Awaited<ReturnType<typeof initElectrum>> | undefined;

0 commit comments

Comments
 (0)