1082815dcSEvan Baconimport * as fs from 'fs';
2082815dcSEvan Baconimport { vol } from 'memfs';
3082815dcSEvan Bacon
4*8a424bebSJames Ideimport { getDirFromFS } from './utils/getDirFromFS';
5ed3bd27bSEvan Baconimport rnFixture from '../../plugins/__tests__/fixtures/react-native-project';
6082815dcSEvan Baconimport * as WarningAggregator from '../../utils/warnings';
7082815dcSEvan Baconimport { getLocales, setLocalesAsync } from '../Locales';
8082815dcSEvan Baconimport { getPbxproj } from '../utils/Xcodeproj';
9082815dcSEvan Bacon
10082815dcSEvan Baconjest.mock('fs');
11082815dcSEvan Baconjest.mock('../../utils/warnings');
12082815dcSEvan Bacon
13082815dcSEvan Bacondescribe('iOS Locales', () => {
14082815dcSEvan Bacon  it(`returns null if no values are provided`, () => {
15082815dcSEvan Bacon    expect(getLocales({})).toBeNull();
16082815dcSEvan Bacon  });
17082815dcSEvan Bacon
18082815dcSEvan Bacon  it(`returns the locales object`, () => {
19082815dcSEvan Bacon    expect(
20082815dcSEvan Bacon      getLocales({
21082815dcSEvan Bacon        locales: {},
22082815dcSEvan Bacon      })
23082815dcSEvan Bacon    ).toStrictEqual({});
24082815dcSEvan Bacon  });
25082815dcSEvan Bacon});
26082815dcSEvan Bacon
27082815dcSEvan Bacondescribe('e2e: iOS locales', () => {
28082815dcSEvan Bacon  const projectRoot = '/app';
29082815dcSEvan Bacon  beforeAll(async () => {
30082815dcSEvan Bacon    vol.fromJSON(
31082815dcSEvan Bacon      {
32ed3bd27bSEvan Bacon        'ios/testproject.xcodeproj/project.pbxproj':
33ed3bd27bSEvan Bacon          rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'],
34082815dcSEvan Bacon        'ios/testproject/AppDelegate.m': '',
35082815dcSEvan Bacon        'lang/fr.json': JSON.stringify({
36082815dcSEvan Bacon          CFBundleDisplayName: 'french-name',
37082815dcSEvan Bacon        }),
38082815dcSEvan Bacon      },
39082815dcSEvan Bacon      projectRoot
40082815dcSEvan Bacon    );
41082815dcSEvan Bacon  });
42082815dcSEvan Bacon
43082815dcSEvan Bacon  afterAll(() => {
44082815dcSEvan Bacon    vol.reset();
45082815dcSEvan Bacon  });
46082815dcSEvan Bacon
47082815dcSEvan Bacon  it('writes all the image files expected', async () => {
48082815dcSEvan Bacon    let project = getPbxproj(projectRoot);
49082815dcSEvan Bacon
50082815dcSEvan Bacon    project = await setLocalesAsync(
51082815dcSEvan Bacon      {
52082815dcSEvan Bacon        locales: {
53082815dcSEvan Bacon          fr: 'lang/fr.json',
54082815dcSEvan Bacon          // doesn't exist
55082815dcSEvan Bacon          xx: 'lang/xx.json',
56082815dcSEvan Bacon          // partially support inlining the JSON so our Expo Config type doesn't conflict with the resolved manifest type.
57082815dcSEvan Bacon          es: { CFBundleDisplayName: 'spanish-name' },
58082815dcSEvan Bacon        },
59082815dcSEvan Bacon      },
60082815dcSEvan Bacon      { project, projectRoot }
61082815dcSEvan Bacon    );
62082815dcSEvan Bacon    // Sync the Xcode project with the changes.
63082815dcSEvan Bacon    fs.writeFileSync(project.filepath, project.writeSync());
64082815dcSEvan Bacon
65082815dcSEvan Bacon    const after = getDirFromFS(vol.toJSON(), projectRoot);
66082815dcSEvan Bacon    const locales = Object.keys(after).filter((value) => value.endsWith('InfoPlist.strings'));
67082815dcSEvan Bacon
68082815dcSEvan Bacon    expect(locales.length).toBe(2);
69082815dcSEvan Bacon    expect(after[locales[0]]).toMatchSnapshot();
70082815dcSEvan Bacon    // Test that the inlined locale is resolved.
71082815dcSEvan Bacon    expect(after[locales[1]]).toMatch(/spanish-name/);
72082815dcSEvan Bacon    // Test a warning is thrown for an invalid locale JSON file.
73082815dcSEvan Bacon    expect(WarningAggregator.addWarningIOS).toHaveBeenCalledWith(
74082815dcSEvan Bacon      'locales.xx',
75082815dcSEvan Bacon      'Failed to parse JSON of locale file for language: xx',
76082815dcSEvan Bacon      'https://docs.expo.dev/distribution/app-stores/#localizing-your-ios-app'
77082815dcSEvan Bacon    );
78082815dcSEvan Bacon  });
79082815dcSEvan Bacon});
80