1import { vol } from 'memfs'; 2import * as path from 'path'; 3 4import rnFixture from '../../plugins/__tests__/fixtures/react-native-project'; 5import { UnexpectedError } from '../../utils/errors'; 6import * as WarningAggregator from '../../utils/warnings'; 7import { 8 findSchemeNames, 9 getAllInfoPlistPaths, 10 getAppDelegate, 11 getXcodeProjectPath, 12} from '../Paths'; 13 14jest.mock('fs'); 15jest.mock('../../utils/warnings'); 16 17describe(findSchemeNames, () => { 18 afterEach(() => { 19 vol.reset(); 20 }); 21 22 it(`returns project path`, () => { 23 vol.fromJSON( 24 { 25 'ios/my-app.xcodeproj/xcshareddata/xcschemes/my-app.xcscheme': '', 26 'ios/my_app.xcodeproj/xcshareddata/xcschemes/my_app.xcscheme': '', 27 'ios/clientTests.xcodeproj/xcshareddata/xcschemes/client.beta.xcscheme': '', 28 }, 29 '/' 30 ); 31 32 expect(findSchemeNames('/')).toStrictEqual(['client.beta', 'my_app', 'my-app']); 33 }); 34}); 35 36describe(getXcodeProjectPath, () => { 37 afterEach(() => { 38 vol.reset(); 39 }); 40 41 it(`returns project path`, () => { 42 vol.fromJSON( 43 { 44 'ios/testproject.xcodeproj/project.pbxproj': 45 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 46 'ios/Podfile': 'content', 47 'ios/TestPod.podspec': 'noop', 48 'ios/testproject/AppDelegate.m': '', 49 }, 50 '/app' 51 ); 52 expect(getXcodeProjectPath('/app')).toBe('/app/ios/testproject.xcodeproj'); 53 }); 54 55 it(`throws when no paths are found`, () => { 56 expect(() => getXcodeProjectPath('/none')).toThrow(UnexpectedError); 57 }); 58 59 it(`warns when multiple paths are found`, () => { 60 vol.fromJSON( 61 { 62 'ios/otherproject.xcodeproj/project.pbxproj': 63 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 64 'ios/testproject.xcodeproj/project.pbxproj': 65 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 66 'ios/testproject/AppDelegate.m': '', 67 }, 68 '/app' 69 ); 70 71 expect(getXcodeProjectPath('/app')).toBe('/app/ios/otherproject.xcodeproj'); 72 expect(WarningAggregator.addWarningIOS).toHaveBeenLastCalledWith( 73 'paths-xcodeproj', 74 'Found multiple *.xcodeproj file paths, using "ios/otherproject.xcodeproj". Ignored paths: ["ios/testproject.xcodeproj"]' 75 ); 76 }); 77 78 it(`selects xcodeproj based on alphabetical order, but picks direct children of ios directory first`, () => { 79 vol.fromJSON( 80 { 81 'ios/otherproject.xcodeproj/project.pbxproj': 82 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 83 'ios/aa/otherproject.xcodeproj/project.pbxproj': 84 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 85 'ios/botherproject.xcodeproj/project.pbxproj': 86 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 87 'ios/testproject.xcodeproj/project.pbxproj': 88 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 89 'ios/testproject/AppDelegate.m': '', 90 }, 91 '/app' 92 ); 93 94 expect(getXcodeProjectPath('/app')).toBe('/app/ios/botherproject.xcodeproj'); 95 expect(WarningAggregator.addWarningIOS).toHaveBeenLastCalledWith( 96 'paths-xcodeproj', 97 'Found multiple *.xcodeproj file paths, using "ios/botherproject.xcodeproj". Ignored paths: ["ios/otherproject.xcodeproj","ios/testproject.xcodeproj","ios/aa/otherproject.xcodeproj"]' 98 ); 99 }); 100 101 it(`warns when multiple paths are found`, () => { 102 vol.fromJSON( 103 { 104 'ios/otherproject.xcodeproj/project.pbxproj': 105 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 106 'ios/testproject.xcodeproj/project.pbxproj': 107 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 108 'ios/testproject/AppDelegate.m': '', 109 }, 110 '/app' 111 ); 112 113 expect(getXcodeProjectPath('/app')).toBe('/app/ios/otherproject.xcodeproj'); 114 expect(WarningAggregator.addWarningIOS).toHaveBeenLastCalledWith( 115 'paths-xcodeproj', 116 'Found multiple *.xcodeproj file paths, using "ios/otherproject.xcodeproj". Ignored paths: ["ios/testproject.xcodeproj"]' 117 ); 118 }); 119 it(`ignores xcodeproj outside of the ios directory`, () => { 120 vol.fromJSON( 121 { 122 'lib/testproject.xcodeproj/project.pbxproj': 123 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 124 }, 125 '/app' 126 ); 127 expect(() => getXcodeProjectPath('/app')).toThrow(UnexpectedError); 128 }); 129}); 130 131describe(getAppDelegate, () => { 132 beforeEach(() => { 133 vol.reset(); 134 }); 135 afterAll(() => { 136 vol.reset(); 137 }); 138 139 it(`returns objc path`, () => { 140 vol.fromJSON( 141 { 142 'ios/testproject.xcodeproj/project.pbxproj': 143 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 144 'ios/Podfile': 'content', 145 'ios/TestPod.podspec': 'noop', 146 'ios/testproject/AppDelegate.m': '', 147 'ios/testproject/AppDelegate.h': '', 148 }, 149 '/objc' 150 ); 151 152 expect(getAppDelegate('/objc')).toStrictEqual({ 153 contents: '', 154 path: '/objc/ios/testproject/AppDelegate.m', 155 language: 'objc', 156 }); 157 }); 158 159 it(`returns C++ (objcpp) path`, () => { 160 vol.fromJSON(rnFixture, '/'); 161 162 expect(getAppDelegate('/')).toStrictEqual({ 163 contents: expect.any(String), 164 path: '/ios/HelloWorld/AppDelegate.mm', 165 language: 'objcpp', 166 }); 167 }); 168 169 it(`returns swift path`, () => { 170 vol.fromJSON( 171 { 172 'ios/testproject.xcodeproj/project.pbxproj': 173 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 174 'ios/Podfile': 'content', 175 'ios/TestPod.podspec': 'noop', 176 'ios/testproject/AppDelegate.swift': '', 177 }, 178 '/swift' 179 ); 180 181 expect(getAppDelegate('/swift')).toStrictEqual({ 182 contents: '', 183 path: '/swift/ios/testproject/AppDelegate.swift', 184 language: 'swift', 185 }); 186 }); 187 188 it(`throws on invalid project`, () => { 189 vol.fromJSON( 190 { 191 'ios/testproject.xcodeproj/project.pbxproj': 192 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 193 'ios/Podfile': 'content', 194 'ios/TestPod.podspec': 'noop', 195 }, 196 '/invalid' 197 ); 198 199 expect(() => getAppDelegate('/invalid')).toThrow(UnexpectedError); 200 expect(() => getAppDelegate('/invalid')).toThrow(/AppDelegate/); 201 }); 202 203 it(`warns when multiple paths are found`, () => { 204 vol.fromJSON( 205 { 206 'ios/testproject.xcodeproj/project.pbxproj': 207 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 208 'ios/Podfile': 'content', 209 'ios/TestPod.podspec': 'noop', 210 'ios/testproject/AppDelegate.swift': '', 211 'ios/testproject/AppDelegate.m': '', 212 'ios/testproject/AppDelegate.h': '', 213 }, 214 '/confusing' 215 ); 216 217 expect(getAppDelegate('/confusing')).toStrictEqual({ 218 contents: '', 219 path: '/confusing/ios/testproject/AppDelegate.m', 220 language: 'objc', 221 }); 222 expect(WarningAggregator.addWarningIOS).toHaveBeenLastCalledWith( 223 'paths-app-delegate', 224 'Found multiple AppDelegate file paths, using "ios/testproject/AppDelegate.m". Ignored paths: ["ios/testproject/AppDelegate.swift"]' 225 ); 226 }); 227}); 228 229describe(getAllInfoPlistPaths, () => { 230 beforeAll(async () => { 231 const project = { 232 'ExampleE2E-tvOS/Info.plist': '', 233 'ExampleE2E/Info.plist': '', 234 'ExampleE2E-tvOSTests/Info.plist': '', 235 'ExampleE2ETests/Info.plist': '', 236 }; 237 vol.fromJSON(project, path.join('/app', 'ios')); 238 vol.fromJSON(project, '/app'); 239 }); 240 241 afterAll(() => { 242 vol.reset(); 243 }); 244 245 it(`gets paths in order`, () => { 246 expect(getAllInfoPlistPaths('/app')).toStrictEqual([ 247 '/app/ios/ExampleE2E/Info.plist', 248 '/app/ios/ExampleE2E-tvOS/Info.plist', 249 '/app/ios/ExampleE2ETests/Info.plist', 250 '/app/ios/ExampleE2E-tvOSTests/Info.plist', 251 ]); 252 }); 253}); 254