Skip to content

Commit 19ee41d

Browse files
committed
add android manifest test
1 parent ee5c24b commit 19ee41d

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// SPDX-License-Identifier: BUSL-1.1; Copyright (c) 2025 Social Connect Labs, Inc.; Licensed under BUSL-1.1 (see LICENSE); Apache-2.0 from 2029-06-11
2+
3+
/**
4+
* @jest-environment node
5+
*/
6+
7+
import * as fs from 'fs';
8+
import * as path from 'path';
9+
10+
describe('Android Manifest Configuration', () => {
11+
const manifestPath = path.join(
12+
__dirname,
13+
'../../android/app/src/main/AndroidManifest.xml',
14+
);
15+
let manifestContent: string;
16+
17+
beforeAll(() => {
18+
// Read the manifest file
19+
manifestContent = fs.readFileSync(manifestPath, 'utf8');
20+
});
21+
22+
describe('Critical Deeplink Configuration', () => {
23+
it('should contain the redirect.self.xyz deeplink intent filter', () => {
24+
// This is the configuration that was accidentally deleted
25+
expect(manifestContent).toContain('android:host="redirect.self.xyz"');
26+
expect(manifestContent).toContain('android:autoVerify="true"');
27+
expect(manifestContent).toContain('android.intent.action.VIEW');
28+
expect(manifestContent).toContain('android.intent.category.BROWSABLE');
29+
expect(manifestContent).toContain('android:scheme="https"');
30+
});
31+
32+
it('should have the deeplink intent filter in the MainActivity', () => {
33+
// Ensure the deeplink is properly configured in the main activity
34+
const mainActivityMatch = manifestContent.match(
35+
/<activity[^>]*android:name="\.MainActivity"[^>]*>(.*?)<\/activity>/s,
36+
);
37+
38+
expect(mainActivityMatch).toBeTruthy();
39+
expect(mainActivityMatch![1]).toContain('redirect.self.xyz');
40+
expect(mainActivityMatch![1]).toContain('android:autoVerify="true"');
41+
});
42+
});
43+
44+
describe('Firebase Configuration', () => {
45+
it('should have Firebase Messaging Service configured', () => {
46+
expect(manifestContent).toContain(
47+
'com.google.firebase.messaging.FirebaseMessagingService',
48+
);
49+
expect(manifestContent).toContain('com.google.firebase.MESSAGING_EVENT');
50+
});
51+
52+
it('should have Firebase metadata configurations', () => {
53+
const firebaseMetaConfigs = [
54+
'com.google.firebase.messaging.default_notification_channel_id',
55+
'com.google.firebase.messaging.default_notification_icon',
56+
'com.google.firebase.messaging.default_notification_color',
57+
];
58+
59+
firebaseMetaConfigs.forEach(config => {
60+
expect(manifestContent).toContain(`android:name="${config}"`);
61+
});
62+
});
63+
64+
it('should have Firebase service properly exported', () => {
65+
// Firebase service should not be exported for security
66+
const serviceMatch = manifestContent.match(
67+
/<service[^>]*android:name="com\.google\.firebase\.messaging\.FirebaseMessagingService"[^>]*>/,
68+
);
69+
expect(serviceMatch).toBeTruthy();
70+
expect(serviceMatch![0]).toContain('android:exported="false"');
71+
});
72+
});
73+
74+
describe('OAuth/AppAuth Configuration', () => {
75+
it('should have AppAuth RedirectUriReceiverActivity configured', () => {
76+
expect(manifestContent).toContain(
77+
'net.openid.appauth.RedirectUriReceiverActivity',
78+
);
79+
expect(manifestContent).toContain('${appAuthRedirectScheme}');
80+
expect(manifestContent).toContain('oauth2redirect');
81+
});
82+
83+
it('should have OAuth activity properly exported', () => {
84+
const oauthActivityMatch = manifestContent.match(
85+
/<activity[^>]*android:name="net\.openid\.appauth\.RedirectUriReceiverActivity"[^>]*>/,
86+
);
87+
expect(oauthActivityMatch).toBeTruthy();
88+
expect(oauthActivityMatch![0]).toContain('android:exported="true"');
89+
});
90+
});
91+
92+
describe('NFC Configuration', () => {
93+
it('should have NFC permission', () => {
94+
expect(manifestContent).toContain('android.permission.NFC');
95+
});
96+
97+
it('should have NFC tech discovery metadata', () => {
98+
expect(manifestContent).toContain('android.nfc.action.TECH_DISCOVERED');
99+
expect(manifestContent).toContain('@xml/nfc_tech_filter');
100+
});
101+
});
102+
103+
describe('Required Permissions', () => {
104+
const criticalPermissions = [
105+
'android.permission.INTERNET',
106+
'android.permission.CAMERA',
107+
'android.permission.NFC',
108+
'android.permission.VIBRATE',
109+
'android.permission.POST_NOTIFICATIONS',
110+
'android.permission.ACCESS_SURFACE_FLINGER',
111+
'android.permission.RECEIVE_BOOT_COMPLETED',
112+
];
113+
114+
criticalPermissions.forEach(permission => {
115+
it(`should contain ${permission} permission`, () => {
116+
expect(manifestContent).toContain(`android:name="${permission}"`);
117+
});
118+
});
119+
});
120+
121+
describe('Main Activity Configuration', () => {
122+
it('should have MainActivity properly configured', () => {
123+
expect(manifestContent).toContain('android:name=".MainActivity"');
124+
expect(manifestContent).toContain('android:exported="true"');
125+
expect(manifestContent).toContain('android:launchMode="singleTop"');
126+
expect(manifestContent).toContain('android:screenOrientation="portrait"');
127+
});
128+
129+
it('should have main launcher intent filter', () => {
130+
expect(manifestContent).toContain('android.intent.action.MAIN');
131+
expect(manifestContent).toContain('android.intent.category.LAUNCHER');
132+
});
133+
134+
it('should have proper config changes handled', () => {
135+
const configChanges = [
136+
'keyboard',
137+
'keyboardHidden',
138+
'orientation',
139+
'screenLayout',
140+
'screenSize',
141+
'smallestScreenSize',
142+
'uiMode',
143+
];
144+
145+
configChanges.forEach(change => {
146+
expect(manifestContent).toContain(change);
147+
});
148+
});
149+
});
150+
151+
describe('Application Configuration', () => {
152+
it('should have MainApplication configured', () => {
153+
expect(manifestContent).toContain('android:name=".MainApplication"');
154+
expect(manifestContent).toContain('android:largeHeap="true"');
155+
expect(manifestContent).toContain('android:supportsRtl="true"');
156+
});
157+
158+
it('should have proper theme and icons configured', () => {
159+
expect(manifestContent).toContain('@style/AppTheme');
160+
expect(manifestContent).toContain('@mipmap/ic_launcher');
161+
});
162+
});
163+
164+
describe('Manifest Structure Validation', () => {
165+
it('should be valid XML structure', () => {
166+
// Basic XML validation - ensure it has proper opening/closing tags
167+
expect(manifestContent).toMatch(/^<manifest[^>]*>/);
168+
expect(manifestContent).toContain('</manifest>');
169+
expect(manifestContent).toContain('<application');
170+
expect(manifestContent).toContain('</application>');
171+
});
172+
173+
it('should have required namespaces', () => {
174+
expect(manifestContent).toContain(
175+
'xmlns:android="http://schemas.android.com/apk/res/android"',
176+
);
177+
expect(manifestContent).toContain(
178+
'xmlns:tools="http://schemas.android.com/tools"',
179+
);
180+
});
181+
});
182+
});

0 commit comments

Comments
 (0)