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