1import plist from '@expo/plist';
2import * as fs from 'fs';
3import { vol } from 'memfs';
4import * as path from 'path';
5
6import rnFixture from '../../plugins/__tests__/fixtures/react-native-project';
7import {
8  ensureApplicationTargetEntitlementsFileConfigured,
9  getEntitlementsPath,
10} from '../Entitlements';
11
12const fsReal = jest.requireActual('fs') as typeof fs;
13
14jest.mock('fs');
15
16const exampleEntitlements = `<?xml version="0.0" encoding="UTF-8"?>
17<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
18<plist version="1.0">
19<dict>
20	<key>special</key>
21	<true/>
22</dict>
23</plist>`;
24
25describe(ensureApplicationTargetEntitlementsFileConfigured, () => {
26  const projectRoot = '/app';
27
28  afterEach(() => {
29    vol.reset();
30  });
31
32  it('creates a new entitlements file when none exists', async () => {
33    vol.fromJSON(rnFixture, projectRoot);
34    const entitlementsPathBefore = getEntitlementsPath(projectRoot);
35    ensureApplicationTargetEntitlementsFileConfigured(projectRoot);
36    const entitlementsPath = getEntitlementsPath(projectRoot);
37    expect(entitlementsPathBefore).toBeNull();
38    expect(entitlementsPath).toBe('/app/ios/HelloWorld/HelloWorld.entitlements');
39
40    // New file has the contents of the old entitlements file
41    const data = plist.parse(await fs.promises.readFile(entitlementsPath!, 'utf8'));
42    expect(data).toStrictEqual({
43      // No entitlements enabled by default
44    });
45  });
46
47  it('creates a new entitlements file if file in XCBuildConfiguration does not exists', async () => {
48    vol.fromJSON(
49      {
50        'ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync(
51          path.join(__dirname, 'fixtures/project-with-entitlements.pbxproj'),
52          'utf-8'
53        ),
54        'ios/testproject/AppDelegate.m': '',
55      },
56      projectRoot
57    );
58    ensureApplicationTargetEntitlementsFileConfigured(projectRoot);
59    const entitlementsPath = getEntitlementsPath(projectRoot);
60    expect(entitlementsPath).toBe('/app/ios/testproject/testproject.entitlements');
61
62    // New file has the contents of the old entitlements file
63    const data = plist.parse(await fs.promises.readFile(entitlementsPath, 'utf8'));
64    expect(data).toStrictEqual({});
65  });
66
67  it('does not create any entitlements files if it already exists', async () => {
68    vol.fromJSON(
69      {
70        'ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync(
71          path.join(__dirname, 'fixtures/project-with-entitlements.pbxproj'),
72          'utf-8'
73        ),
74        'ios/testapp/example.entitlements': exampleEntitlements,
75        'ios/testproject/AppDelegate.m': '',
76      },
77      projectRoot
78    );
79    ensureApplicationTargetEntitlementsFileConfigured(projectRoot);
80    const entitlementsPath = getEntitlementsPath(projectRoot);
81    expect(entitlementsPath).toBe('/app/ios/testapp/example.entitlements');
82
83    // New file has the contents of the old entitlements file
84    const data = plist.parse(await fs.promises.readFile(entitlementsPath, 'utf8'));
85    expect(data).toStrictEqual({ special: true });
86
87    // entitlement file in default location does not exist
88    expect(fs.existsSync('/app/ios/testproject/testproject.entitlements')).toBe(false);
89  });
90});
91
92describe(getEntitlementsPath, () => {
93  const projectRoot = '/app';
94
95  afterEach(() => {
96    vol.reset();
97  });
98
99  it('returns null if CODE_SIGN_ENTITLEMENTS is not specified', async () => {
100    vol.fromJSON(
101      {
102        'ios/testproject.xcodeproj/project.pbxproj':
103          rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'],
104        'ios/testproject/AppDelegate.m': '',
105      },
106      projectRoot
107    );
108
109    const entitlementsPath = getEntitlementsPath(projectRoot);
110    expect(entitlementsPath).toBeNull();
111  });
112  it('returns path if CODE_SIGN_ENTITLEMENTS is specified and file exists', async () => {
113    vol.fromJSON(
114      {
115        'ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync(
116          path.join(__dirname, 'fixtures/project-with-entitlements.pbxproj'),
117          'utf-8'
118        ),
119        'ios/testapp/example.entitlements': exampleEntitlements,
120        'ios/testproject/AppDelegate.m': '',
121      },
122      projectRoot
123    );
124
125    const entitlementsPath = getEntitlementsPath(projectRoot);
126    expect(entitlementsPath).toBe('/app/ios/testapp/example.entitlements');
127  });
128});
129