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