Skip to content

Commit e2e1f86

Browse files
committed
Cleanup & dramatically speed up the new tests
1 parent 47e0da9 commit e2e1f86

File tree

5 files changed

+67
-81
lines changed

5 files changed

+67
-81
lines changed

integration-tests/src/adb.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,33 @@ async function getScreenSize(): Promise<{ width: number; height: number }> {
1515
return { width: 1080, height: 1920 };
1616
}
1717

18+
async function isScreenOnAndUnlocked(): Promise<boolean> {
19+
try {
20+
const powerState = await adbShell('dumpsys power | grep -E "mWakefulness|mHoldingDisplaySuspendBlocker"');
21+
const isAwake = powerState.includes('Awake') || powerState.includes('mHoldingDisplaySuspendBlocker=true');
22+
23+
if (!isAwake) return false;
24+
25+
const windowState = await adbShell('dumpsys window | grep -E "mDreamingLockscreen|mShowingLockscreen"');
26+
const isLocked = windowState.includes('mDreamingLockscreen=true') || windowState.includes('mShowingLockscreen=true');
27+
28+
return !isLocked;
29+
} catch {
30+
return false;
31+
}
32+
}
33+
1834
export async function wakeScreen(): Promise<void> {
35+
if (await isScreenOnAndUnlocked()) {
36+
return;
37+
}
38+
1939
await adb(['shell', 'input', 'keyevent', 'KEYCODE_WAKEUP']);
20-
await delay(500);
40+
await delay(300);
41+
42+
if (await isScreenOnAndUnlocked()) {
43+
return;
44+
}
2145

2246
const { width, height } = await getScreenSize();
2347
const centerX = Math.round(width / 2);
@@ -29,9 +53,6 @@ export async function wakeScreen(): Promise<void> {
2953
String(centerX), String(swipeEndY),
3054
'300'
3155
]);
32-
await delay(500);
33-
34-
await adb(['shell', 'input', 'keyevent', 'KEYCODE_MENU']);
3556
await delay(300);
3657
}
3758

integration-tests/src/httptoolkit-app.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,19 @@ export async function activateVpn(connectUrl: string, options: {
2929
'-d', connectUrl
3030
]);
3131

32-
await delay(1000);
32+
await delay(500);
3333

3434
if (handleDialogs) {
35-
const dialogHandled = await handleVpnPermissionDialog(timeout);
35+
await handleVpnPermissionDialog(timeout);
3636

37-
if (!dialogHandled) {
38-
const vpnActive = await isVpnActive();
39-
if (!vpnActive) {
40-
console.warn('VPN permission dialog may not have been handled');
41-
}
37+
if (await isVpnActive()) {
38+
handleNotificationPermissionDialog(2000).catch(() => {});
39+
return true;
4240
}
4341

44-
await handleNotificationPermissionDialog(5000);
42+
await handleNotificationPermissionDialog(2000);
4543
}
4644

47-
await delay(2000);
4845
return await isVpnActive();
4946
}
5047

integration-tests/src/ui-automation.ts

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ export async function dumpUiHierarchy(): Promise<string> {
2222
}
2323
}
2424

25-
export async function findElementByText(text: string, exactMatch: boolean = false): Promise<{ x: number; y: number } | null> {
26-
const xml = await dumpUiHierarchy();
27-
25+
function findTextInXml(xml: string, text: string, exactMatch: boolean = false): { x: number; y: number } | null {
2826
const escapedText = text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2927
const pattern = exactMatch
3028
? new RegExp(`text="${escapedText}"[^>]*bounds="\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"`)
@@ -49,6 +47,11 @@ export async function findElementByText(text: string, exactMatch: boolean = fals
4947
return null;
5048
}
5149

50+
export async function findElementByText(text: string, exactMatch: boolean = false): Promise<{ x: number; y: number } | null> {
51+
const xml = await dumpUiHierarchy();
52+
return findTextInXml(xml, text, exactMatch);
53+
}
54+
5255
export async function findElementByResourceId(resourceId: string): Promise<{ x: number; y: number } | null> {
5356
const xml = await dumpUiHierarchy();
5457

@@ -100,15 +103,12 @@ export async function pressBack(): Promise<void> {
100103

101104
async function setupScreenLockViaUi(pin: string = '1234'): Promise<boolean> {
102105
try {
103-
console.log(' Attempting to set up screen lock via UI...');
104-
105106
let tapped = await tapText('Set screen lock', true);
106107
if (!tapped) {
107108
tapped = await tapText('Set a screen lock', false);
108109
}
109110

110111
if (!tapped) {
111-
console.log(' Could not find "Set screen lock" button');
112112
return false;
113113
}
114114

@@ -120,7 +120,6 @@ async function setupScreenLockViaUi(pin: string = '1234'): Promise<boolean> {
120120
}
121121

122122
if (!tapped) {
123-
console.log(' Could not find PIN option');
124123
await pressBack();
125124
return false;
126125
}
@@ -153,10 +152,8 @@ async function setupScreenLockViaUi(pin: string = '1234'): Promise<boolean> {
153152
await delay(500);
154153
}
155154

156-
console.log(' Screen lock setup via UI complete');
157155
return true;
158-
} catch (e) {
159-
console.log(' Error setting up screen lock via UI:', e);
156+
} catch {
160157
return false;
161158
}
162159
}
@@ -167,15 +164,13 @@ async function setupScreenLockViaUi(pin: string = '1234'): Promise<boolean> {
167164
*/
168165
export async function handleVpnPermissionDialog(timeoutMs: number = 15000): Promise<boolean> {
169166
const startTime = Date.now();
170-
let lastXml = '';
171167

172168
while (Date.now() - startTime < timeoutMs) {
173169
if (await checkVpnActive()) {
174170
return true;
175171
}
176172

177173
const xml = await dumpUiHierarchy();
178-
lastXml = xml;
179174

180175
if (xml.toLowerCase().includes('connected') &&
181176
xml.toLowerCase().includes('disconnect') &&
@@ -191,9 +186,9 @@ export async function handleVpnPermissionDialog(timeoutMs: number = 15000): Prom
191186

192187
if (xml.toLowerCase().includes('send you notifications') ||
193188
(xml.toLowerCase().includes('notification') && xml.toLowerCase().includes('allow'))) {
194-
console.log(' Found notification permission dialog, tapping Allow...');
195-
if (await tapText('Allow', true)) {
196-
console.log(' Tapped Allow on notification dialog');
189+
const allowButton = findTextInXml(xml, 'Allow', true);
190+
if (allowButton) {
191+
await tap(allowButton.x, allowButton.y);
197192
await delay(1000);
198193
continue;
199194
}
@@ -222,41 +217,39 @@ export async function handleVpnPermissionDialog(timeoutMs: number = 15000): Prom
222217
xml.toLowerCase().includes('set up vpn');
223218

224219
if (xml.toLowerCase().includes('manual setup required')) {
225-
console.log(' Found "Manual setup required" dialog from app');
226-
227-
if (await tapText('Skip', true)) {
228-
console.log(' Tapped Skip on manual setup dialog');
220+
const skipButton = findTextInXml(xml, 'Skip', true);
221+
if (skipButton) {
222+
await tap(skipButton.x, skipButton.y);
229223
await delay(2000);
230224

225+
if (await checkVpnActive()) {
226+
return true;
227+
}
228+
231229
const afterSkipXml = await dumpUiHierarchy();
232230
if (afterSkipXml.toLowerCase().includes('connection request') ||
233231
afterSkipXml.toLowerCase().includes('set up vpn')) {
234-
console.log(' VPN dialog appeared after skip, continuing...');
235232
continue;
236233
}
237234

238-
if (afterSkipXml.toLowerCase().includes('disconnected')) {
239-
console.log(' App returned to disconnected state after skip');
235+
await delay(1000);
236+
if (await checkVpnActive()) {
237+
return true;
240238
}
241239
continue;
242240
}
243241

244-
if (await tapText('Cancel', true)) {
245-
console.log(' Tapped Cancel on manual setup dialog');
246-
await delay(1000);
247-
return false;
248-
}
242+
await delay(500);
243+
continue;
249244
}
250245

251246
if (isVpnDialog) {
252-
console.log(` Found VPN dialog (package: ${currentPackage}), looking for button...`);
253-
254247
const positiveButtons = ['OK', 'ALLOW', 'Allow', 'Connect', 'CONNECT', 'Yes', 'YES', 'I trust this app'];
255248

256249
for (const buttonText of positiveButtons) {
257-
const tapped = await tapText(buttonText, true);
258-
if (tapped) {
259-
console.log(` Tapped "${buttonText}" button`);
250+
const button = findTextInXml(xml, buttonText, true);
251+
if (button) {
252+
await tap(button.x, button.y);
260253
await delay(1000);
261254
return true;
262255
}
@@ -269,50 +262,39 @@ export async function handleVpnPermissionDialog(timeoutMs: number = 15000): Prom
269262
];
270263

271264
for (const buttonId of buttonIds) {
272-
const tapped = await tapResourceId(buttonId);
273-
if (tapped) {
274-
console.log(` Tapped button with ID ${buttonId}`);
265+
const pattern = new RegExp(`resource-id="${buttonId}"[^>]*bounds="\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"`);
266+
const match = xml.match(pattern);
267+
if (match) {
268+
const [, x1, y1, x2, y2] = match.map(Number);
269+
await tap(Math.round((x1 + x2) / 2), Math.round((y1 + y2) / 2));
275270
await delay(1000);
276271
return true;
277272
}
278273
}
279-
280-
console.log(' Could not find button to tap. UI contains:');
281-
const buttonMatches = xml.match(/text="[^"]+"/g) || [];
282-
console.log(' Text elements:', buttonMatches.slice(0, 10).join(', '));
283274
}
284275

285276
if (xml.toLowerCase().includes('set a screen lock') ||
286277
xml.toLowerCase().includes('set screen lock') ||
287278
(xml.toLowerCase().includes('screen lock') && xml.toLowerCase().includes('security'))) {
288-
console.log(' Found "Set screen lock" dialog - need to set up screen lock via UI');
289-
290279
const lockSetUp = await setupScreenLockViaUi();
291280
if (lockSetUp) {
292-
console.log(' Screen lock set up, retrying VPN permission...');
293281
await pressBack();
294282
await delay(1000);
295283
continue;
296284
} else {
297-
console.log(' Could not set up screen lock via UI');
298285
await pressBack();
299286
await delay(500);
300287
return false;
301288
}
302289
}
303290

304291
if (xml.toLowerCase().includes('oh no') || xml.toLowerCase().includes("couldn't connect")) {
305-
console.log(' App showing error state');
306292
return false;
307293
}
308294

309295
await delay(500);
310296
}
311297

312-
console.log(' VPN dialog timeout. Last UI state had texts:');
313-
const textMatches = lastXml.match(/text="[^"]+"/g) || [];
314-
console.log(' ', textMatches.slice(0, 15).join(', '));
315-
316298
return false;
317299
}
318300

integration-tests/test/integration.spec.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
stopApp,
1717
captureDebugScreenshot
1818
} from '../src/httptoolkit-app.js';
19-
import { adbShell, wakeScreen } from '../src/adb.js';
19+
import { adbShell } from '../src/adb.js';
2020

2121
async function httpRequest(host: string, port: number, method: string, path: string, options: {
2222
headers?: Record<string, string>;
@@ -124,7 +124,6 @@ describe('HTTP Toolkit Android Integration Tests', function() {
124124
});
125125

126126
beforeEach(async function() {
127-
await wakeScreen();
128127
await resetTestState();
129128
ctx = await createTestContext(8080);
130129
});
@@ -149,8 +148,6 @@ describe('HTTP Toolkit Android Integration Tests', function() {
149148
const proxyInfo = ctx.proxy.getProxyInfo();
150149
const connectUrl = buildConnectUrl(proxyInfo);
151150

152-
console.log('Testing activation with URL:', connectUrl);
153-
154151
const activated = await activateVpn(connectUrl, { timeout: 45000 });
155152
expect(activated, 'VPN should be activated').to.be.true;
156153

@@ -262,15 +259,10 @@ describe('HTTP Toolkit Android Integration Tests', function() {
262259
});
263260

264261
it('should handle UDP packets (DNS query)', async function() {
265-
try {
266-
await sendUdp('8.8.8.8', 53, 'test', {
267-
timeout: 5000,
268-
waitForResponse: false
269-
});
270-
expect(true).to.be.true;
271-
} catch (e) {
272-
console.log('UDP test note:', e);
273-
}
262+
await sendUdp('8.8.8.8', 53, 'test', {
263+
timeout: 5000,
264+
waitForResponse: false
265+
});
274266
});
275267

276268
it('should not crash VPN when receiving UDP traffic', async function() {
@@ -297,7 +289,6 @@ describe('HTTP Toolkit Android Integration Tests', function() {
297289

298290
it('should handle ICMP ping through VPN', async function() {
299291
const result = await ping('8.8.8.8', 3, 10000);
300-
console.log('Ping output:', result.output);
301292
expect(result.transmitted).to.equal(3);
302293
});
303294

@@ -370,8 +361,7 @@ describe('HTTP Toolkit Android Integration Tests', function() {
370361
handleDialogs: true
371362
});
372363

373-
const vpnActive = await isVpnActive();
374-
console.log('Unreachable proxy result:', { activated, vpnActive });
364+
expect(activated).to.be.false;
375365
});
376366

377367
it('should handle invalid connect URL', async function() {

integration-tests/test/setup.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,5 @@ export async function resetTestState(): Promise<void> {
6969
export const mochaHooks = {
7070
async beforeAll() {
7171
await globalSetup();
72-
},
73-
74-
async afterEach() {
75-
await new Promise(resolve => setTimeout(resolve, 500));
7672
}
7773
};

0 commit comments

Comments
 (0)