1import * as fs from 'fs';
2import { vol } from 'memfs';
3
4import rnFixture from '../../plugins/__tests__/fixtures/react-native-project';
5import * as WarningAggregator from '../../utils/warnings';
6import { getLocales, setLocalesAsync } from '../Locales';
7import { getPbxproj } from '../utils/Xcodeproj';
8import { getDirFromFS } from './utils/getDirFromFS';
9
10jest.mock('fs');
11jest.mock('../../utils/warnings');
12
13describe('iOS Locales', () => {
14  it(`returns null if no values are provided`, () => {
15    expect(getLocales({})).toBeNull();
16  });
17
18  it(`returns the locales object`, () => {
19    expect(
20      getLocales({
21        locales: {},
22      })
23    ).toStrictEqual({});
24  });
25});
26
27describe('e2e: iOS locales', () => {
28  const projectRoot = '/app';
29  beforeAll(async () => {
30    vol.fromJSON(
31      {
32        'ios/testproject.xcodeproj/project.pbxproj':
33          rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'],
34        'ios/testproject/AppDelegate.m': '',
35        'lang/fr.json': JSON.stringify({
36          CFBundleDisplayName: 'french-name',
37        }),
38      },
39      projectRoot
40    );
41  });
42
43  afterAll(() => {
44    vol.reset();
45  });
46
47  it('writes all the image files expected', async () => {
48    let project = getPbxproj(projectRoot);
49
50    project = await setLocalesAsync(
51      {
52        locales: {
53          fr: 'lang/fr.json',
54          // doesn't exist
55          xx: 'lang/xx.json',
56          // partially support inlining the JSON so our Expo Config type doesn't conflict with the resolved manifest type.
57          es: { CFBundleDisplayName: 'spanish-name' },
58        },
59      },
60      { project, projectRoot }
61    );
62    // Sync the Xcode project with the changes.
63    fs.writeFileSync(project.filepath, project.writeSync());
64
65    const after = getDirFromFS(vol.toJSON(), projectRoot);
66    const locales = Object.keys(after).filter((value) => value.endsWith('InfoPlist.strings'));
67
68    expect(locales.length).toBe(2);
69    expect(after[locales[0]]).toMatchSnapshot();
70    // Test that the inlined locale is resolved.
71    expect(after[locales[1]]).toMatch(/spanish-name/);
72    // Test a warning is thrown for an invalid locale JSON file.
73    expect(WarningAggregator.addWarningIOS).toHaveBeenCalledWith(
74      'locales.xx',
75      'Failed to parse JSON of locale file for language: xx',
76      'https://docs.expo.dev/distribution/app-stores/#localizing-your-ios-app'
77    );
78  });
79});
80