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