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