1import fs from 'fs';
2import { vol } from 'memfs';
3import path from 'path';
4
5import * as Updates from '../Updates';
6import { getPbxproj } from '../utils/Xcodeproj';
7
8const fsReal = jest.requireActual('fs') as typeof fs;
9jest.mock('fs');
10jest.mock('resolve-from');
11
12const { silent } = require('resolve-from');
13
14const fixturesPath = path.resolve(__dirname, 'fixtures');
15const sampleCodeSigningCertificatePath = path.resolve(fixturesPath, 'codeSigningCertificate.pem');
16
17describe('iOS Updates config', () => {
18  beforeEach(() => {
19    const resolveFrom = require('resolve-from');
20    resolveFrom.silent = silent;
21    vol.reset();
22  });
23
24  it('sets the correct values in Expo.plist', () => {
25    vol.fromJSON({
26      '/app/hello': fsReal.readFileSync(sampleCodeSigningCertificatePath, 'utf-8'),
27    });
28
29    expect(
30      Updates.setUpdatesConfig(
31        '/app',
32        {
33          sdkVersion: '37.0.0',
34          slug: 'my-app',
35          owner: 'owner',
36          updates: {
37            enabled: false,
38            fallbackToCacheTimeout: 2000,
39            checkAutomatically: 'ON_ERROR_RECOVERY',
40            codeSigningCertificate: 'hello',
41            codeSigningMetadata: {
42              alg: 'rsa-v1_5-sha256',
43              keyid: 'test',
44            },
45          },
46        },
47        {} as any,
48        'user',
49        '0.11.0'
50      )
51    ).toMatchObject({
52      EXUpdatesEnabled: false,
53      EXUpdatesURL: 'https://exp.host/@owner/my-app',
54      EXUpdatesCheckOnLaunch: 'ERROR_RECOVERY_ONLY',
55      EXUpdatesLaunchWaitMs: 2000,
56      EXUpdatesSDKVersion: '37.0.0',
57      EXUpdatesCodeSigningCertificate: fsReal.readFileSync(
58        sampleCodeSigningCertificatePath,
59        'utf-8'
60      ),
61      EXUpdatesCodeSigningMetadata: { alg: 'rsa-v1_5-sha256', keyid: 'test' },
62    });
63  });
64
65  describe(Updates.ensureBundleReactNativePhaseContainsConfigurationScript, () => {
66    beforeEach(() => {
67      vol.reset();
68      const resolveFrom = require('resolve-from');
69      resolveFrom.silent = silent;
70    });
71
72    it("adds create-manifest-ios.sh line to the 'Bundle React Native code and images' build phase ", () => {
73      vol.fromJSON(
74        {
75          'ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync(
76            path.join(__dirname, 'fixtures/project-without-create-manifest-ios.pbxproj'),
77            'utf-8'
78          ),
79          'node_modules/expo-updates/scripts/create-manifest-ios.sh': 'whatever',
80        },
81        '/app'
82      );
83
84      const xcodeProject = getPbxproj('/app');
85      Updates.ensureBundleReactNativePhaseContainsConfigurationScript('/app', xcodeProject);
86      const bundleReactNative = Updates.getBundleReactNativePhase(xcodeProject);
87      expect(bundleReactNative.shellScript).toMatchSnapshot();
88    });
89
90    it('fixes the path to create-manifest-ios.sh in case of a monorepo', () => {
91      // Pseudo node module resolution since actually mocking it could prove challenging.
92      // In a yarn workspace, resolve-from would be able to locate a module in any node_module folder if properly linked.
93      const resolveFrom = require('resolve-from');
94      resolveFrom.silent = (p, a) => {
95        return silent(path.join(p, '..'), a);
96      };
97
98      vol.fromJSON(
99        {
100          'workspace/ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync(
101            path.join(
102              __dirname,
103              'fixtures/project-with-incorrect-create-manifest-ios-path.pbxproj'
104            ),
105            'utf-8'
106          ),
107          'node_modules/expo-updates/scripts/create-manifest-ios.sh': 'whatever',
108        },
109        '/app'
110      );
111      const xcodeProject = getPbxproj('/app/workspace');
112      Updates.ensureBundleReactNativePhaseContainsConfigurationScript(
113        '/app/workspace',
114        xcodeProject
115      );
116      const bundleReactNative = Updates.getBundleReactNativePhase(xcodeProject);
117      expect(bundleReactNative.shellScript).toMatchSnapshot();
118    });
119  });
120});
121