1import { ExpoConfig } from 'expo/config'; 2import { fs, vol } from 'memfs'; 3import * as path from 'path'; 4 5import { 6 getNotificationColor, 7 getNotificationIcon, 8 setNotificationIconAsync, 9 setNotificationSounds, 10} from '../withNotificationsAndroid'; 11 12export function getDirFromFS(fsJSON: Record<string, string | null>, rootDir: string) { 13 return Object.entries(fsJSON) 14 .filter(([path, value]) => value !== null && path.startsWith(rootDir)) 15 .reduce<Record<string, string>>( 16 (acc, [path, fileContent]) => ({ 17 ...acc, 18 [path.substring(rootDir.length).startsWith('/') 19 ? path.substring(rootDir.length + 1) 20 : path.substring(rootDir.length)]: fileContent, 21 }), 22 {} 23 ); 24} 25 26const SAMPLE_COLORS_XML = `<?xml version="1.0" encoding="utf-8"?> 27 <resources> 28 <!-- Below line is handled by '@expo/configure-splash-screen' command and it's discouraged to modify it manually --> 29 <color name="splashscreen_background">#FFFFFF</color> 30 </resources> 31 `; 32 33jest.mock('fs'); 34 35const fsReal = jest.requireActual('fs') as typeof fs; 36 37const LIST_OF_GENERATED_NOTIFICATION_FILES = [ 38 'android/app/src/main/res/drawable-mdpi/notification_icon.png', 39 'android/app/src/main/res/drawable-hdpi/notification_icon.png', 40 'android/app/src/main/res/drawable-xhdpi/notification_icon.png', 41 'android/app/src/main/res/drawable-xxhdpi/notification_icon.png', 42 'android/app/src/main/res/drawable-xxxhdpi/notification_icon.png', 43 'android/app/src/main/res/values/colors.xml', 44 'assets/notificationIcon.png', 45 'assets/notificationSound.wav', 46 'android/app/src/main/res/raw/notificationSound.wav', 47]; 48 49const iconPath = path.resolve(__dirname, './fixtures/icon.png'); 50const soundPath = path.resolve(__dirname, './fixtures/cat.wav'); 51 52const projectRoot = '/app'; 53 54describe('Android notifications configuration', () => { 55 beforeEach(async () => { 56 const icon = fsReal.readFileSync(iconPath); 57 const sound = fsReal.readFileSync(soundPath); 58 vol.fromJSON( 59 { './android/app/src/main/res/values/colors.xml': SAMPLE_COLORS_XML }, 60 projectRoot 61 ); 62 setUpDrawableDirectories(); 63 vol.mkdirpSync('/app/assets'); 64 vol.writeFileSync('/app/assets/notificationIcon.png', icon); 65 vol.writeFileSync('/app/assets/notificationSound.wav', sound); 66 }); 67 68 afterEach(() => { 69 vol.reset(); 70 }); 71 72 afterAll(() => { 73 jest.unmock('@expo/image-utils'); 74 jest.unmock('fs'); 75 }); 76 77 it(`returns null if no config provided`, () => { 78 expect(getNotificationIcon({} as ExpoConfig)).toBeNull(); 79 expect(getNotificationColor({} as ExpoConfig)).toBeNull(); 80 }); 81 82 it(`returns config if provided`, () => { 83 expect(getNotificationIcon({ notification: { icon: './myIcon.png' } } as ExpoConfig)).toMatch( 84 './myIcon.png' 85 ); 86 expect(getNotificationColor({ notification: { color: '#123456' } } as ExpoConfig)).toMatch( 87 '#123456' 88 ); 89 }); 90 91 it('writes all the asset files (sounds and images) as expected', async () => { 92 await setNotificationIconAsync(projectRoot, '/app/assets/notificationIcon.png'); 93 setNotificationSounds(projectRoot, ['/app/assets/notificationSound.wav']); 94 95 const after = getDirFromFS(vol.toJSON(), projectRoot); 96 expect(Object.keys(after).sort()).toEqual(LIST_OF_GENERATED_NOTIFICATION_FILES.sort()); 97 }); 98 99 it('Safely remove icon if it exists, and ignore if it doesnt', async () => { 100 const before = getDirFromFS(vol.toJSON(), projectRoot); 101 // first set the icon 102 await setNotificationIconAsync(projectRoot, '/app/assets/notificationIcon.png'); 103 104 // now remove 105 await setNotificationIconAsync(projectRoot, null); 106 107 const after = getDirFromFS(vol.toJSON(), projectRoot); 108 expect(before).toMatchObject(after); 109 110 // now remove again to make sure we don't throw in that case 111 await setNotificationIconAsync(projectRoot, null); 112 113 const final = getDirFromFS(vol.toJSON(), projectRoot); 114 expect(before).toMatchObject(final); 115 }); 116}); 117 118function setUpDrawableDirectories() { 119 vol.mkdirpSync('/app/android/app/src/main/res/drawable-mdpi'); 120 vol.mkdirpSync('/app/android/app/src/main/res/drawable-hdpi'); 121 vol.mkdirpSync('/app/android/app/src/main/res/drawable-xhdpi'); 122 vol.mkdirpSync('/app/android/app/src/main/res/drawable-xxhdpi'); 123 vol.mkdirpSync('/app/android/app/src/main/res/drawable-xxxhdpi'); 124} 125