├── .gitignore ├── Podfile ├── Podfile.lock ├── README.md ├── SimpleNoteStarter.zip ├── SimpleNoteTakingApp.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── SimpleNoteTakingApp.xcworkspace └── contents.xcworkspacedata ├── SimpleNoteTakingApp ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Config │ └── Constants.swift ├── Extensions │ ├── UIColor+Extensions.swift │ ├── UIStoryboard+Extensions.swift │ ├── UITableView+Extensions.swift │ └── UIViewController+Extensions.swift ├── Info.plist ├── Models │ └── Note.swift └── ViewControllers │ ├── HomeViewController.swift │ ├── LoginViewController.swift │ └── NoteViewController.swift └── SimpleNoteTakingAppTests ├── Extensions └── KIF+Extensions.swift ├── Features ├── BaseUITests.swift ├── HomeTests.swift └── LoginTests.swift ├── Info.plist ├── SimpleNoteTakingAppTests-Bridging-Header.h └── Steps ├── CommonSteps.swift ├── HomeSteps.swift └── LoginSteps.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | Carthage 26 | Pods/ 27 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '9.0' 2 | 3 | target 'SimpleNoteTakingApp' do 4 | use_frameworks! 5 | 6 | pod 'Realm', git: 'https://github.com/realm/realm-cocoa.git', branch: 'master', submodules: true 7 | pod 'RealmSwift', git: 'https://github.com/realm/realm-cocoa.git', branch: 'master', submodules: true 8 | 9 | target 'SimpleNoteTakingAppTests' do 10 | inherit! :search_paths 11 | pod 'KIF', git: 'https://github.com/kif-framework/KIF.git', branch: 'master' 12 | pod 'Nimble', :git => 'https://github.com/Quick/Nimble.git', :commit => 'db706fc' 13 | end 14 | 15 | post_install do |installer| 16 | installer.pods_project.targets.each do |target| 17 | target.build_configurations.each do |config| 18 | config.build_settings['SWIFT_VERSION'] = '3.0' 19 | end 20 | end 21 | end 22 | 23 | end 24 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - KIF (3.5.1): 3 | - KIF/Core (= 3.5.1) 4 | - KIF/Core (3.5.1) 5 | - Nimble (5.0.0-alpha.30p1) 6 | - Realm (2.0.2): 7 | - Realm/Headers (= 2.0.2) 8 | - Realm/Headers (2.0.2) 9 | - RealmSwift (2.0.2): 10 | - Realm (= 2.0.2) 11 | 12 | DEPENDENCIES: 13 | - KIF (from `https://github.com/kif-framework/KIF.git`, branch `master`) 14 | - Nimble (from `https://github.com/Quick/Nimble.git`, commit `db706fc`) 15 | - Realm (from `https://github.com/realm/realm-cocoa.git`, branch `master`) 16 | - RealmSwift (from `https://github.com/realm/realm-cocoa.git`, branch `master`) 17 | 18 | EXTERNAL SOURCES: 19 | KIF: 20 | :branch: master 21 | :git: https://github.com/kif-framework/KIF.git 22 | Nimble: 23 | :commit: db706fc 24 | :git: https://github.com/Quick/Nimble.git 25 | Realm: 26 | :branch: master 27 | :git: https://github.com/realm/realm-cocoa.git 28 | :submodules: true 29 | RealmSwift: 30 | :branch: master 31 | :git: https://github.com/realm/realm-cocoa.git 32 | :submodules: true 33 | 34 | CHECKOUT OPTIONS: 35 | KIF: 36 | :commit: 13f543388167c575d0e47f94f52b0f2c7038ed2c 37 | :git: https://github.com/kif-framework/KIF.git 38 | Nimble: 39 | :commit: db706fc 40 | :git: https://github.com/Quick/Nimble.git 41 | Realm: 42 | :commit: 69b4144c71d0224a82f2948884286906c173c2fc 43 | :git: https://github.com/realm/realm-cocoa.git 44 | :submodules: true 45 | RealmSwift: 46 | :commit: 69b4144c71d0224a82f2948884286906c173c2fc 47 | :git: https://github.com/realm/realm-cocoa.git 48 | :submodules: true 49 | 50 | SPEC CHECKSUMS: 51 | KIF: 082eb65279e51c3092923802849eb796a04982ab 52 | Nimble: c5b995b4cd57789ec44b0cfb79640fc00e61a8c7 53 | Realm: 0f5a194af0b7e6158b83db41b4ee1a00be7ddf1a 54 | RealmSwift: 0eb5070d851cba7c66e841ca756d83609dc78bc8 55 | 56 | PODFILE CHECKSUM: 252b3b12b1328969d4ef2309ecb9af67cce2cbef 57 | 58 | COCOAPODS: 1.0.1 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Simple Note App for demonstrating automated UI testing on iOS 2 | 3 | You probably have heard about automated tests before. People talk about it a lot these days, especially when the topic is about software quality. 4 | 5 | They say that if you don't write any tests for your project, you're in big trouble. It may not affect you at the moment. But in the long run, it would become a huge technical debt. 6 | 7 | That's true. 8 | 9 | Project with no tests is impossibile to maintain when it gets big and there are multiple developers involved. As you change something in the code, things start to break. You don't even know that it breaks until your boss comes to your desk and starts yelling. You know that feeling, right? 10 | 11 | So, it's better to know a thing or two about testing so that you can improve your project quality and also improve yourself as a software engineer. 12 | 13 | There are 2 types of automated tests in iOS: 14 | 15 | 30 | 31 | 32 | For the full tutorial, please refer to the link below: 33 | 34 | http://www.appcoda.com/automated-ui-test 35 | -------------------------------------------------------------------------------- /SimpleNoteStarter.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcoda/SimpleNote/9a27d4c94fdc20dba1a000e036824e6ffe989e7a/SimpleNoteStarter.zip -------------------------------------------------------------------------------- /SimpleNoteTakingApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | archiveVersion 6 | 1 7 | classes 8 | 9 | objectVersion 10 | 46 11 | objects 12 | 13 | 060CE08A55E090BD9B062DA2 14 | 15 | children 16 | 17 | 5E0E95450D6880AF7638F8F5 18 | 759F63F7D7423A62927BA011 19 | 20 | isa 21 | PBXGroup 22 | name 23 | Frameworks 24 | sourceTree 25 | <group> 26 | 27 | 08EF98704AF410F61BBA9BD1 28 | 29 | includeInIndex 30 | 1 31 | isa 32 | PBXFileReference 33 | lastKnownFileType 34 | text.xcconfig 35 | name 36 | Pods-SimpleNoteTakingApp.debug.xcconfig 37 | path 38 | Pods/Target Support Files/Pods-SimpleNoteTakingApp/Pods-SimpleNoteTakingApp.debug.xcconfig 39 | sourceTree 40 | <group> 41 | 42 | 0E89A0DB0B1948A8A9D2AE83 43 | 44 | buildActionMask 45 | 2147483647 46 | files 47 | 48 | inputPaths 49 | 50 | isa 51 | PBXShellScriptBuildPhase 52 | name 53 | [CP] Embed Pods Frameworks 54 | outputPaths 55 | 56 | runOnlyForDeploymentPostprocessing 57 | 0 58 | shellPath 59 | /bin/sh 60 | shellScript 61 | "${SRCROOT}/Pods/Target Support Files/Pods-SimpleNoteTakingApp/Pods-SimpleNoteTakingApp-frameworks.sh" 62 | 63 | showEnvVarsInLog 64 | 0 65 | 66 | 18EEB4331DB63DA0008D21CC 67 | 68 | children 69 | 70 | 18EEB4341DB63DA0008D21CC 71 | 72 | isa 73 | PBXGroup 74 | path 75 | Extensions 76 | sourceTree 77 | <group> 78 | 79 | 18EEB4341DB63DA0008D21CC 80 | 81 | fileEncoding 82 | 4 83 | isa 84 | PBXFileReference 85 | lastKnownFileType 86 | sourcecode.swift 87 | path 88 | KIF+Extensions.swift 89 | sourceTree 90 | <group> 91 | 92 | 18EEB4351DB63DA0008D21CC 93 | 94 | children 95 | 96 | 18EEB4361DB63DA0008D21CC 97 | 18EEB4371DB63DA0008D21CC 98 | 18EEB4381DB63DA0008D21CC 99 | 100 | isa 101 | PBXGroup 102 | path 103 | Features 104 | sourceTree 105 | <group> 106 | 107 | 18EEB4361DB63DA0008D21CC 108 | 109 | fileEncoding 110 | 4 111 | isa 112 | PBXFileReference 113 | lastKnownFileType 114 | sourcecode.swift 115 | path 116 | BaseUITests.swift 117 | sourceTree 118 | <group> 119 | 120 | 18EEB4371DB63DA0008D21CC 121 | 122 | fileEncoding 123 | 4 124 | isa 125 | PBXFileReference 126 | lastKnownFileType 127 | sourcecode.swift 128 | path 129 | HomeTests.swift 130 | sourceTree 131 | <group> 132 | 133 | 18EEB4381DB63DA0008D21CC 134 | 135 | fileEncoding 136 | 4 137 | isa 138 | PBXFileReference 139 | lastKnownFileType 140 | sourcecode.swift 141 | path 142 | LoginTests.swift 143 | sourceTree 144 | <group> 145 | 146 | 18EEB4391DB63DA0008D21CC 147 | 148 | fileEncoding 149 | 4 150 | isa 151 | PBXFileReference 152 | lastKnownFileType 153 | sourcecode.c.h 154 | path 155 | SimpleNoteTakingAppTests-Bridging-Header.h 156 | sourceTree 157 | <group> 158 | 159 | 18EEB43A1DB63DA0008D21CC 160 | 161 | children 162 | 163 | 18EEB43B1DB63DA0008D21CC 164 | 18EEB43C1DB63DA0008D21CC 165 | 18EEB43D1DB63DA0008D21CC 166 | 167 | isa 168 | PBXGroup 169 | path 170 | Steps 171 | sourceTree 172 | <group> 173 | 174 | 18EEB43B1DB63DA0008D21CC 175 | 176 | fileEncoding 177 | 4 178 | isa 179 | PBXFileReference 180 | lastKnownFileType 181 | sourcecode.swift 182 | path 183 | CommonSteps.swift 184 | sourceTree 185 | <group> 186 | 187 | 18EEB43C1DB63DA0008D21CC 188 | 189 | fileEncoding 190 | 4 191 | isa 192 | PBXFileReference 193 | lastKnownFileType 194 | sourcecode.swift 195 | path 196 | HomeSteps.swift 197 | sourceTree 198 | <group> 199 | 200 | 18EEB43D1DB63DA0008D21CC 201 | 202 | fileEncoding 203 | 4 204 | isa 205 | PBXFileReference 206 | lastKnownFileType 207 | sourcecode.swift 208 | path 209 | LoginSteps.swift 210 | sourceTree 211 | <group> 212 | 213 | 18EEB43E1DB63DA0008D21CC 214 | 215 | fileRef 216 | 18EEB4341DB63DA0008D21CC 217 | isa 218 | PBXBuildFile 219 | 220 | 18EEB43F1DB63DA0008D21CC 221 | 222 | fileRef 223 | 18EEB4361DB63DA0008D21CC 224 | isa 225 | PBXBuildFile 226 | 227 | 18EEB4401DB63DA0008D21CC 228 | 229 | fileRef 230 | 18EEB4371DB63DA0008D21CC 231 | isa 232 | PBXBuildFile 233 | 234 | 18EEB4411DB63DA0008D21CC 235 | 236 | fileRef 237 | 18EEB4381DB63DA0008D21CC 238 | isa 239 | PBXBuildFile 240 | 241 | 18EEB4421DB63DA0008D21CC 242 | 243 | fileRef 244 | 18EEB43B1DB63DA0008D21CC 245 | isa 246 | PBXBuildFile 247 | 248 | 18EEB4431DB63DA0008D21CC 249 | 250 | fileRef 251 | 18EEB43C1DB63DA0008D21CC 252 | isa 253 | PBXBuildFile 254 | 255 | 18EEB4441DB63DA0008D21CC 256 | 257 | fileRef 258 | 18EEB43D1DB63DA0008D21CC 259 | isa 260 | PBXBuildFile 261 | 262 | 18EEB4451DB63F02008D21CC 263 | 264 | fileEncoding 265 | 4 266 | isa 267 | PBXFileReference 268 | lastKnownFileType 269 | sourcecode.swift 270 | path 271 | UIColor+Extensions.swift 272 | sourceTree 273 | <group> 274 | 275 | 18EEB4461DB63F02008D21CC 276 | 277 | fileRef 278 | 18EEB4451DB63F02008D21CC 279 | isa 280 | PBXBuildFile 281 | 282 | 21A573759537D14B921EB3E5 283 | 284 | buildActionMask 285 | 2147483647 286 | files 287 | 288 | inputPaths 289 | 290 | isa 291 | PBXShellScriptBuildPhase 292 | name 293 | [CP] Copy Pods Resources 294 | outputPaths 295 | 296 | runOnlyForDeploymentPostprocessing 297 | 0 298 | shellPath 299 | /bin/sh 300 | shellScript 301 | "${SRCROOT}/Pods/Target Support Files/Pods-SimpleNoteTakingAppTests/Pods-SimpleNoteTakingAppTests-resources.sh" 302 | 303 | showEnvVarsInLog 304 | 0 305 | 306 | 2787861573BE73ED11C5055A 307 | 308 | fileRef 309 | 5E0E95450D6880AF7638F8F5 310 | isa 311 | PBXBuildFile 312 | 313 | 2BD90F8AC0B31C6DB7A3DFD7 314 | 315 | includeInIndex 316 | 1 317 | isa 318 | PBXFileReference 319 | lastKnownFileType 320 | text.xcconfig 321 | name 322 | Pods-SimpleNoteTakingAppTests.debug.xcconfig 323 | path 324 | Pods/Target Support Files/Pods-SimpleNoteTakingAppTests/Pods-SimpleNoteTakingAppTests.debug.xcconfig 325 | sourceTree 326 | <group> 327 | 328 | 2DB49DEAC0C4217C1693F5C9 329 | 330 | fileRef 331 | 759F63F7D7423A62927BA011 332 | isa 333 | PBXBuildFile 334 | 335 | 5C5AADD9672AD06049495439 336 | 337 | includeInIndex 338 | 1 339 | isa 340 | PBXFileReference 341 | lastKnownFileType 342 | text.xcconfig 343 | name 344 | Pods-SimpleNoteTakingAppTests.release.xcconfig 345 | path 346 | Pods/Target Support Files/Pods-SimpleNoteTakingAppTests/Pods-SimpleNoteTakingAppTests.release.xcconfig 347 | sourceTree 348 | <group> 349 | 350 | 5E0E95450D6880AF7638F8F5 351 | 352 | explicitFileType 353 | wrapper.framework 354 | includeInIndex 355 | 0 356 | isa 357 | PBXFileReference 358 | path 359 | Pods_SimpleNoteTakingApp.framework 360 | sourceTree 361 | BUILT_PRODUCTS_DIR 362 | 363 | 72CDFA668CDF702B7FE001DB 364 | 365 | buildActionMask 366 | 2147483647 367 | files 368 | 369 | inputPaths 370 | 371 | isa 372 | PBXShellScriptBuildPhase 373 | name 374 | [CP] Embed Pods Frameworks 375 | outputPaths 376 | 377 | runOnlyForDeploymentPostprocessing 378 | 0 379 | shellPath 380 | /bin/sh 381 | shellScript 382 | "${SRCROOT}/Pods/Target Support Files/Pods-SimpleNoteTakingAppTests/Pods-SimpleNoteTakingAppTests-frameworks.sh" 383 | 384 | showEnvVarsInLog 385 | 0 386 | 387 | 759F63F7D7423A62927BA011 388 | 389 | explicitFileType 390 | wrapper.framework 391 | includeInIndex 392 | 0 393 | isa 394 | PBXFileReference 395 | path 396 | Pods_SimpleNoteTakingAppTests.framework 397 | sourceTree 398 | BUILT_PRODUCTS_DIR 399 | 400 | 98D18A9B4A5B6B800CD523F6 401 | 402 | buildActionMask 403 | 2147483647 404 | files 405 | 406 | inputPaths 407 | 408 | isa 409 | PBXShellScriptBuildPhase 410 | name 411 | [CP] Check Pods Manifest.lock 412 | outputPaths 413 | 414 | runOnlyForDeploymentPostprocessing 415 | 0 416 | shellPath 417 | /bin/sh 418 | shellScript 419 | diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null 420 | if [[ $? != 0 ]] ; then 421 | cat << EOM 422 | error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation. 423 | EOM 424 | exit 1 425 | fi 426 | 427 | showEnvVarsInLog 428 | 0 429 | 430 | B20011C818B47727914AC427 431 | 432 | includeInIndex 433 | 1 434 | isa 435 | PBXFileReference 436 | lastKnownFileType 437 | text.xcconfig 438 | name 439 | Pods-SimpleNoteTakingApp.release.xcconfig 440 | path 441 | Pods/Target Support Files/Pods-SimpleNoteTakingApp/Pods-SimpleNoteTakingApp.release.xcconfig 442 | sourceTree 443 | <group> 444 | 445 | BD3958C1EB521C3903704132 446 | 447 | buildActionMask 448 | 2147483647 449 | files 450 | 451 | inputPaths 452 | 453 | isa 454 | PBXShellScriptBuildPhase 455 | name 456 | [CP] Check Pods Manifest.lock 457 | outputPaths 458 | 459 | runOnlyForDeploymentPostprocessing 460 | 0 461 | shellPath 462 | /bin/sh 463 | shellScript 464 | diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null 465 | if [[ $? != 0 ]] ; then 466 | cat << EOM 467 | error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation. 468 | EOM 469 | exit 1 470 | fi 471 | 472 | showEnvVarsInLog 473 | 0 474 | 475 | BE27EEC73A32BAAEE7388A9F 476 | 477 | children 478 | 479 | 08EF98704AF410F61BBA9BD1 480 | B20011C818B47727914AC427 481 | 2BD90F8AC0B31C6DB7A3DFD7 482 | 5C5AADD9672AD06049495439 483 | 484 | isa 485 | PBXGroup 486 | name 487 | Pods 488 | sourceTree 489 | <group> 490 | 491 | E5DF510F84E77A3CDCC1CE86 492 | 493 | buildActionMask 494 | 2147483647 495 | files 496 | 497 | inputPaths 498 | 499 | isa 500 | PBXShellScriptBuildPhase 501 | name 502 | [CP] Copy Pods Resources 503 | outputPaths 504 | 505 | runOnlyForDeploymentPostprocessing 506 | 0 507 | shellPath 508 | /bin/sh 509 | shellScript 510 | "${SRCROOT}/Pods/Target Support Files/Pods-SimpleNoteTakingApp/Pods-SimpleNoteTakingApp-resources.sh" 511 | 512 | showEnvVarsInLog 513 | 0 514 | 515 | F3594B2C1D99FCC70046DA07 516 | 517 | children 518 | 519 | F3594B371D99FCC70046DA07 520 | F3594B4C1D99FCC70046DA07 521 | F3594B361D99FCC70046DA07 522 | BE27EEC73A32BAAEE7388A9F 523 | 060CE08A55E090BD9B062DA2 524 | 525 | isa 526 | PBXGroup 527 | sourceTree 528 | <group> 529 | 530 | F3594B2D1D99FCC70046DA07 531 | 532 | attributes 533 | 534 | LastSwiftUpdateCheck 535 | 0730 536 | LastUpgradeCheck 537 | 0800 538 | ORGANIZATIONNAME 539 | AppCoda 540 | TargetAttributes 541 | 542 | F3594B341D99FCC70046DA07 543 | 544 | CreatedOnToolsVersion 545 | 7.3 546 | LastSwiftMigration 547 | 0800 548 | 549 | F3594B481D99FCC70046DA07 550 | 551 | CreatedOnToolsVersion 552 | 7.3 553 | LastSwiftMigration 554 | 0800 555 | TestTargetID 556 | F3594B341D99FCC70046DA07 557 | 558 | 559 | 560 | buildConfigurationList 561 | F3594B301D99FCC70046DA07 562 | compatibilityVersion 563 | Xcode 3.2 564 | developmentRegion 565 | English 566 | hasScannedForEncodings 567 | 0 568 | isa 569 | PBXProject 570 | knownRegions 571 | 572 | en 573 | Base 574 | 575 | mainGroup 576 | F3594B2C1D99FCC70046DA07 577 | productRefGroup 578 | F3594B361D99FCC70046DA07 579 | projectDirPath 580 | 581 | projectReferences 582 | 583 | projectRoot 584 | 585 | targets 586 | 587 | F3594B341D99FCC70046DA07 588 | F3594B481D99FCC70046DA07 589 | 590 | 591 | F3594B301D99FCC70046DA07 592 | 593 | buildConfigurations 594 | 595 | F3594B501D99FCC70046DA07 596 | F3594B511D99FCC70046DA07 597 | 598 | defaultConfigurationIsVisible 599 | 0 600 | defaultConfigurationName 601 | Release 602 | isa 603 | XCConfigurationList 604 | 605 | F3594B311D99FCC70046DA07 606 | 607 | buildActionMask 608 | 2147483647 609 | files 610 | 611 | F3594B731D9B552D0046DA07 612 | 18EEB4461DB63F02008D21CC 613 | F3594B391D99FCC70046DA07 614 | F3594B751D9B552D0046DA07 615 | F3594B721D9B552D0046DA07 616 | F3594B791D9B552D0046DA07 617 | F3594B781D9B552D0046DA07 618 | F3594B741D9B552D0046DA07 619 | F3594B771D9B552D0046DA07 620 | F3594B761D9B552D0046DA07 621 | 622 | isa 623 | PBXSourcesBuildPhase 624 | runOnlyForDeploymentPostprocessing 625 | 0 626 | 627 | F3594B321D99FCC70046DA07 628 | 629 | buildActionMask 630 | 2147483647 631 | files 632 | 633 | 2787861573BE73ED11C5055A 634 | 635 | isa 636 | PBXFrameworksBuildPhase 637 | runOnlyForDeploymentPostprocessing 638 | 0 639 | 640 | F3594B331D99FCC70046DA07 641 | 642 | buildActionMask 643 | 2147483647 644 | files 645 | 646 | F3594B431D99FCC70046DA07 647 | F3594B401D99FCC70046DA07 648 | F3594B3E1D99FCC70046DA07 649 | 650 | isa 651 | PBXResourcesBuildPhase 652 | runOnlyForDeploymentPostprocessing 653 | 0 654 | 655 | F3594B341D99FCC70046DA07 656 | 657 | buildConfigurationList 658 | F3594B521D99FCC70046DA07 659 | buildPhases 660 | 661 | BD3958C1EB521C3903704132 662 | F3594B311D99FCC70046DA07 663 | F3594B321D99FCC70046DA07 664 | F3594B331D99FCC70046DA07 665 | 0E89A0DB0B1948A8A9D2AE83 666 | E5DF510F84E77A3CDCC1CE86 667 | 668 | buildRules 669 | 670 | dependencies 671 | 672 | isa 673 | PBXNativeTarget 674 | name 675 | SimpleNoteTakingApp 676 | productName 677 | SimpleNoteTakingApp 678 | productReference 679 | F3594B351D99FCC70046DA07 680 | productType 681 | com.apple.product-type.application 682 | 683 | F3594B351D99FCC70046DA07 684 | 685 | explicitFileType 686 | wrapper.application 687 | includeInIndex 688 | 0 689 | isa 690 | PBXFileReference 691 | path 692 | SimpleNoteTakingApp.app 693 | sourceTree 694 | BUILT_PRODUCTS_DIR 695 | 696 | F3594B361D99FCC70046DA07 697 | 698 | children 699 | 700 | F3594B351D99FCC70046DA07 701 | F3594B491D99FCC70046DA07 702 | 703 | isa 704 | PBXGroup 705 | name 706 | Products 707 | sourceTree 708 | <group> 709 | 710 | F3594B371D99FCC70046DA07 711 | 712 | children 713 | 714 | F3594B7A1D9B55400046DA07 715 | F3594B661D9B552D0046DA07 716 | F3594B681D9B552D0046DA07 717 | F3594B6C1D9B552D0046DA07 718 | F3594B6E1D9B552D0046DA07 719 | F3594B3C1D99FCC70046DA07 720 | F3594B381D99FCC70046DA07 721 | 722 | isa 723 | PBXGroup 724 | path 725 | SimpleNoteTakingApp 726 | sourceTree 727 | <group> 728 | 729 | F3594B381D99FCC70046DA07 730 | 731 | isa 732 | PBXFileReference 733 | lastKnownFileType 734 | sourcecode.swift 735 | path 736 | AppDelegate.swift 737 | sourceTree 738 | <group> 739 | 740 | F3594B391D99FCC70046DA07 741 | 742 | fileRef 743 | F3594B381D99FCC70046DA07 744 | isa 745 | PBXBuildFile 746 | 747 | F3594B3C1D99FCC70046DA07 748 | 749 | children 750 | 751 | F3594B3D1D99FCC70046DA07 752 | 753 | isa 754 | PBXVariantGroup 755 | name 756 | Main.storyboard 757 | sourceTree 758 | <group> 759 | 760 | F3594B3D1D99FCC70046DA07 761 | 762 | isa 763 | PBXFileReference 764 | lastKnownFileType 765 | file.storyboard 766 | name 767 | Base 768 | path 769 | Base.lproj/Main.storyboard 770 | sourceTree 771 | <group> 772 | 773 | F3594B3E1D99FCC70046DA07 774 | 775 | fileRef 776 | F3594B3C1D99FCC70046DA07 777 | isa 778 | PBXBuildFile 779 | 780 | F3594B3F1D99FCC70046DA07 781 | 782 | isa 783 | PBXFileReference 784 | lastKnownFileType 785 | folder.assetcatalog 786 | path 787 | Assets.xcassets 788 | sourceTree 789 | <group> 790 | 791 | F3594B401D99FCC70046DA07 792 | 793 | fileRef 794 | F3594B3F1D99FCC70046DA07 795 | isa 796 | PBXBuildFile 797 | 798 | F3594B411D99FCC70046DA07 799 | 800 | children 801 | 802 | F3594B421D99FCC70046DA07 803 | 804 | isa 805 | PBXVariantGroup 806 | name 807 | LaunchScreen.storyboard 808 | sourceTree 809 | <group> 810 | 811 | F3594B421D99FCC70046DA07 812 | 813 | isa 814 | PBXFileReference 815 | lastKnownFileType 816 | file.storyboard 817 | name 818 | Base 819 | path 820 | Base.lproj/LaunchScreen.storyboard 821 | sourceTree 822 | <group> 823 | 824 | F3594B431D99FCC70046DA07 825 | 826 | fileRef 827 | F3594B411D99FCC70046DA07 828 | isa 829 | PBXBuildFile 830 | 831 | F3594B441D99FCC70046DA07 832 | 833 | isa 834 | PBXFileReference 835 | lastKnownFileType 836 | text.plist.xml 837 | path 838 | Info.plist 839 | sourceTree 840 | <group> 841 | 842 | F3594B451D99FCC70046DA07 843 | 844 | buildActionMask 845 | 2147483647 846 | files 847 | 848 | 18EEB4431DB63DA0008D21CC 849 | 18EEB43F1DB63DA0008D21CC 850 | 18EEB4401DB63DA0008D21CC 851 | 18EEB43E1DB63DA0008D21CC 852 | 18EEB4421DB63DA0008D21CC 853 | 18EEB4441DB63DA0008D21CC 854 | 18EEB4411DB63DA0008D21CC 855 | 856 | isa 857 | PBXSourcesBuildPhase 858 | runOnlyForDeploymentPostprocessing 859 | 0 860 | 861 | F3594B461D99FCC70046DA07 862 | 863 | buildActionMask 864 | 2147483647 865 | files 866 | 867 | 2DB49DEAC0C4217C1693F5C9 868 | 869 | isa 870 | PBXFrameworksBuildPhase 871 | runOnlyForDeploymentPostprocessing 872 | 0 873 | 874 | F3594B471D99FCC70046DA07 875 | 876 | buildActionMask 877 | 2147483647 878 | files 879 | 880 | isa 881 | PBXResourcesBuildPhase 882 | runOnlyForDeploymentPostprocessing 883 | 0 884 | 885 | F3594B481D99FCC70046DA07 886 | 887 | buildConfigurationList 888 | F3594B551D99FCC70046DA07 889 | buildPhases 890 | 891 | 98D18A9B4A5B6B800CD523F6 892 | F3594B451D99FCC70046DA07 893 | F3594B461D99FCC70046DA07 894 | F3594B471D99FCC70046DA07 895 | 72CDFA668CDF702B7FE001DB 896 | 21A573759537D14B921EB3E5 897 | 898 | buildRules 899 | 900 | dependencies 901 | 902 | F3594B4B1D99FCC70046DA07 903 | 904 | isa 905 | PBXNativeTarget 906 | name 907 | SimpleNoteTakingAppTests 908 | productName 909 | SimpleNoteTakingAppTests 910 | productReference 911 | F3594B491D99FCC70046DA07 912 | productType 913 | com.apple.product-type.bundle.unit-test 914 | 915 | F3594B491D99FCC70046DA07 916 | 917 | explicitFileType 918 | wrapper.cfbundle 919 | includeInIndex 920 | 0 921 | isa 922 | PBXFileReference 923 | path 924 | SimpleNoteTakingAppTests.xctest 925 | sourceTree 926 | BUILT_PRODUCTS_DIR 927 | 928 | F3594B4A1D99FCC70046DA07 929 | 930 | containerPortal 931 | F3594B2D1D99FCC70046DA07 932 | isa 933 | PBXContainerItemProxy 934 | proxyType 935 | 1 936 | remoteGlobalIDString 937 | F3594B341D99FCC70046DA07 938 | remoteInfo 939 | SimpleNoteTakingApp 940 | 941 | F3594B4B1D99FCC70046DA07 942 | 943 | isa 944 | PBXTargetDependency 945 | target 946 | F3594B341D99FCC70046DA07 947 | targetProxy 948 | F3594B4A1D99FCC70046DA07 949 | 950 | F3594B4C1D99FCC70046DA07 951 | 952 | children 953 | 954 | 18EEB4331DB63DA0008D21CC 955 | 18EEB4351DB63DA0008D21CC 956 | 18EEB4391DB63DA0008D21CC 957 | 18EEB43A1DB63DA0008D21CC 958 | F3594B4F1D99FCC70046DA07 959 | 960 | isa 961 | PBXGroup 962 | path 963 | SimpleNoteTakingAppTests 964 | sourceTree 965 | <group> 966 | 967 | F3594B4F1D99FCC70046DA07 968 | 969 | isa 970 | PBXFileReference 971 | lastKnownFileType 972 | text.plist.xml 973 | path 974 | Info.plist 975 | sourceTree 976 | <group> 977 | 978 | F3594B501D99FCC70046DA07 979 | 980 | buildSettings 981 | 982 | ALWAYS_SEARCH_USER_PATHS 983 | NO 984 | CLANG_ANALYZER_NONNULL 985 | YES 986 | CLANG_CXX_LANGUAGE_STANDARD 987 | gnu++0x 988 | CLANG_CXX_LIBRARY 989 | libc++ 990 | CLANG_ENABLE_MODULES 991 | YES 992 | CLANG_ENABLE_OBJC_ARC 993 | YES 994 | CLANG_WARN_BOOL_CONVERSION 995 | YES 996 | CLANG_WARN_CONSTANT_CONVERSION 997 | YES 998 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE 999 | YES_ERROR 1000 | CLANG_WARN_EMPTY_BODY 1001 | YES 1002 | CLANG_WARN_ENUM_CONVERSION 1003 | YES 1004 | CLANG_WARN_INFINITE_RECURSION 1005 | YES 1006 | CLANG_WARN_INT_CONVERSION 1007 | YES 1008 | CLANG_WARN_OBJC_ROOT_CLASS 1009 | YES_ERROR 1010 | CLANG_WARN_SUSPICIOUS_MOVE 1011 | YES 1012 | CLANG_WARN_UNREACHABLE_CODE 1013 | YES 1014 | CLANG_WARN__DUPLICATE_METHOD_MATCH 1015 | YES 1016 | CODE_SIGN_IDENTITY[sdk=iphoneos*] 1017 | iPhone Developer 1018 | COPY_PHASE_STRIP 1019 | NO 1020 | DEBUG_INFORMATION_FORMAT 1021 | dwarf 1022 | ENABLE_STRICT_OBJC_MSGSEND 1023 | YES 1024 | ENABLE_TESTABILITY 1025 | YES 1026 | GCC_C_LANGUAGE_STANDARD 1027 | gnu99 1028 | GCC_DYNAMIC_NO_PIC 1029 | NO 1030 | GCC_NO_COMMON_BLOCKS 1031 | YES 1032 | GCC_OPTIMIZATION_LEVEL 1033 | 0 1034 | GCC_PREPROCESSOR_DEFINITIONS 1035 | 1036 | DEBUG=1 1037 | $(inherited) 1038 | 1039 | GCC_WARN_64_TO_32_BIT_CONVERSION 1040 | YES 1041 | GCC_WARN_ABOUT_RETURN_TYPE 1042 | YES_ERROR 1043 | GCC_WARN_UNDECLARED_SELECTOR 1044 | YES 1045 | GCC_WARN_UNINITIALIZED_AUTOS 1046 | YES_AGGRESSIVE 1047 | GCC_WARN_UNUSED_FUNCTION 1048 | YES 1049 | GCC_WARN_UNUSED_VARIABLE 1050 | YES 1051 | IPHONEOS_DEPLOYMENT_TARGET 1052 | 9.3 1053 | MTL_ENABLE_DEBUG_INFO 1054 | YES 1055 | ONLY_ACTIVE_ARCH 1056 | YES 1057 | SDKROOT 1058 | iphoneos 1059 | SWIFT_OPTIMIZATION_LEVEL 1060 | -Onone 1061 | 1062 | isa 1063 | XCBuildConfiguration 1064 | name 1065 | Debug 1066 | 1067 | F3594B511D99FCC70046DA07 1068 | 1069 | buildSettings 1070 | 1071 | ALWAYS_SEARCH_USER_PATHS 1072 | NO 1073 | CLANG_ANALYZER_NONNULL 1074 | YES 1075 | CLANG_CXX_LANGUAGE_STANDARD 1076 | gnu++0x 1077 | CLANG_CXX_LIBRARY 1078 | libc++ 1079 | CLANG_ENABLE_MODULES 1080 | YES 1081 | CLANG_ENABLE_OBJC_ARC 1082 | YES 1083 | CLANG_WARN_BOOL_CONVERSION 1084 | YES 1085 | CLANG_WARN_CONSTANT_CONVERSION 1086 | YES 1087 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE 1088 | YES_ERROR 1089 | CLANG_WARN_EMPTY_BODY 1090 | YES 1091 | CLANG_WARN_ENUM_CONVERSION 1092 | YES 1093 | CLANG_WARN_INFINITE_RECURSION 1094 | YES 1095 | CLANG_WARN_INT_CONVERSION 1096 | YES 1097 | CLANG_WARN_OBJC_ROOT_CLASS 1098 | YES_ERROR 1099 | CLANG_WARN_SUSPICIOUS_MOVE 1100 | YES 1101 | CLANG_WARN_UNREACHABLE_CODE 1102 | YES 1103 | CLANG_WARN__DUPLICATE_METHOD_MATCH 1104 | YES 1105 | CODE_SIGN_IDENTITY[sdk=iphoneos*] 1106 | iPhone Developer 1107 | COPY_PHASE_STRIP 1108 | NO 1109 | DEBUG_INFORMATION_FORMAT 1110 | dwarf-with-dsym 1111 | ENABLE_NS_ASSERTIONS 1112 | NO 1113 | ENABLE_STRICT_OBJC_MSGSEND 1114 | YES 1115 | GCC_C_LANGUAGE_STANDARD 1116 | gnu99 1117 | GCC_NO_COMMON_BLOCKS 1118 | YES 1119 | GCC_WARN_64_TO_32_BIT_CONVERSION 1120 | YES 1121 | GCC_WARN_ABOUT_RETURN_TYPE 1122 | YES_ERROR 1123 | GCC_WARN_UNDECLARED_SELECTOR 1124 | YES 1125 | GCC_WARN_UNINITIALIZED_AUTOS 1126 | YES_AGGRESSIVE 1127 | GCC_WARN_UNUSED_FUNCTION 1128 | YES 1129 | GCC_WARN_UNUSED_VARIABLE 1130 | YES 1131 | IPHONEOS_DEPLOYMENT_TARGET 1132 | 9.3 1133 | MTL_ENABLE_DEBUG_INFO 1134 | NO 1135 | SDKROOT 1136 | iphoneos 1137 | SWIFT_OPTIMIZATION_LEVEL 1138 | -Owholemodule 1139 | VALIDATE_PRODUCT 1140 | YES 1141 | 1142 | isa 1143 | XCBuildConfiguration 1144 | name 1145 | Release 1146 | 1147 | F3594B521D99FCC70046DA07 1148 | 1149 | buildConfigurations 1150 | 1151 | F3594B531D99FCC70046DA07 1152 | F3594B541D99FCC70046DA07 1153 | 1154 | defaultConfigurationIsVisible 1155 | 0 1156 | defaultConfigurationName 1157 | Release 1158 | isa 1159 | XCConfigurationList 1160 | 1161 | F3594B531D99FCC70046DA07 1162 | 1163 | baseConfigurationReference 1164 | 08EF98704AF410F61BBA9BD1 1165 | buildSettings 1166 | 1167 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES 1168 | YES 1169 | ASSETCATALOG_COMPILER_APPICON_NAME 1170 | AppIcon 1171 | INFOPLIST_FILE 1172 | SimpleNoteTakingApp/Info.plist 1173 | LD_RUNPATH_SEARCH_PATHS 1174 | $(inherited) @executable_path/Frameworks 1175 | PRODUCT_BUNDLE_IDENTIFIER 1176 | appcoda.SimpleNoteTakingApp 1177 | PRODUCT_NAME 1178 | $(TARGET_NAME) 1179 | SWIFT_VERSION 1180 | 3.0 1181 | 1182 | isa 1183 | XCBuildConfiguration 1184 | name 1185 | Debug 1186 | 1187 | F3594B541D99FCC70046DA07 1188 | 1189 | baseConfigurationReference 1190 | B20011C818B47727914AC427 1191 | buildSettings 1192 | 1193 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES 1194 | YES 1195 | ASSETCATALOG_COMPILER_APPICON_NAME 1196 | AppIcon 1197 | INFOPLIST_FILE 1198 | SimpleNoteTakingApp/Info.plist 1199 | LD_RUNPATH_SEARCH_PATHS 1200 | $(inherited) @executable_path/Frameworks 1201 | PRODUCT_BUNDLE_IDENTIFIER 1202 | appcoda.SimpleNoteTakingApp 1203 | PRODUCT_NAME 1204 | $(TARGET_NAME) 1205 | SWIFT_VERSION 1206 | 3.0 1207 | 1208 | isa 1209 | XCBuildConfiguration 1210 | name 1211 | Release 1212 | 1213 | F3594B551D99FCC70046DA07 1214 | 1215 | buildConfigurations 1216 | 1217 | F3594B561D99FCC70046DA07 1218 | F3594B571D99FCC70046DA07 1219 | 1220 | defaultConfigurationIsVisible 1221 | 0 1222 | defaultConfigurationName 1223 | Release 1224 | isa 1225 | XCConfigurationList 1226 | 1227 | F3594B561D99FCC70046DA07 1228 | 1229 | baseConfigurationReference 1230 | 2BD90F8AC0B31C6DB7A3DFD7 1231 | buildSettings 1232 | 1233 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES 1234 | YES 1235 | BUNDLE_LOADER 1236 | $(TEST_HOST) 1237 | INFOPLIST_FILE 1238 | SimpleNoteTakingAppTests/Info.plist 1239 | LD_RUNPATH_SEARCH_PATHS 1240 | $(inherited) @executable_path/Frameworks @loader_path/Frameworks 1241 | PRODUCT_BUNDLE_IDENTIFIER 1242 | appcoda.SimpleNoteTakingAppTests 1243 | PRODUCT_NAME 1244 | $(TARGET_NAME) 1245 | SWIFT_VERSION 1246 | 3.0 1247 | TEST_HOST 1248 | $(BUILT_PRODUCTS_DIR)/SimpleNoteTakingApp.app/SimpleNoteTakingApp 1249 | 1250 | isa 1251 | XCBuildConfiguration 1252 | name 1253 | Debug 1254 | 1255 | F3594B571D99FCC70046DA07 1256 | 1257 | baseConfigurationReference 1258 | 5C5AADD9672AD06049495439 1259 | buildSettings 1260 | 1261 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES 1262 | YES 1263 | BUNDLE_LOADER 1264 | $(TEST_HOST) 1265 | INFOPLIST_FILE 1266 | SimpleNoteTakingAppTests/Info.plist 1267 | LD_RUNPATH_SEARCH_PATHS 1268 | $(inherited) @executable_path/Frameworks @loader_path/Frameworks 1269 | PRODUCT_BUNDLE_IDENTIFIER 1270 | appcoda.SimpleNoteTakingAppTests 1271 | PRODUCT_NAME 1272 | $(TARGET_NAME) 1273 | SWIFT_VERSION 1274 | 3.0 1275 | TEST_HOST 1276 | $(BUILT_PRODUCTS_DIR)/SimpleNoteTakingApp.app/SimpleNoteTakingApp 1277 | 1278 | isa 1279 | XCBuildConfiguration 1280 | name 1281 | Release 1282 | 1283 | F3594B661D9B552D0046DA07 1284 | 1285 | children 1286 | 1287 | F3594B671D9B552D0046DA07 1288 | 1289 | isa 1290 | PBXGroup 1291 | path 1292 | Config 1293 | sourceTree 1294 | <group> 1295 | 1296 | F3594B671D9B552D0046DA07 1297 | 1298 | fileEncoding 1299 | 4 1300 | isa 1301 | PBXFileReference 1302 | lastKnownFileType 1303 | sourcecode.swift 1304 | path 1305 | Constants.swift 1306 | sourceTree 1307 | <group> 1308 | 1309 | F3594B681D9B552D0046DA07 1310 | 1311 | children 1312 | 1313 | 18EEB4451DB63F02008D21CC 1314 | F3594B691D9B552D0046DA07 1315 | F3594B6A1D9B552D0046DA07 1316 | F3594B6B1D9B552D0046DA07 1317 | 1318 | isa 1319 | PBXGroup 1320 | path 1321 | Extensions 1322 | sourceTree 1323 | <group> 1324 | 1325 | F3594B691D9B552D0046DA07 1326 | 1327 | fileEncoding 1328 | 4 1329 | isa 1330 | PBXFileReference 1331 | lastKnownFileType 1332 | sourcecode.swift 1333 | path 1334 | UIStoryboard+Extensions.swift 1335 | sourceTree 1336 | <group> 1337 | 1338 | F3594B6A1D9B552D0046DA07 1339 | 1340 | fileEncoding 1341 | 4 1342 | isa 1343 | PBXFileReference 1344 | lastKnownFileType 1345 | sourcecode.swift 1346 | path 1347 | UITableView+Extensions.swift 1348 | sourceTree 1349 | <group> 1350 | 1351 | F3594B6B1D9B552D0046DA07 1352 | 1353 | fileEncoding 1354 | 4 1355 | isa 1356 | PBXFileReference 1357 | lastKnownFileType 1358 | sourcecode.swift 1359 | path 1360 | UIViewController+Extensions.swift 1361 | sourceTree 1362 | <group> 1363 | 1364 | F3594B6C1D9B552D0046DA07 1365 | 1366 | children 1367 | 1368 | F3594B6D1D9B552D0046DA07 1369 | 1370 | isa 1371 | PBXGroup 1372 | path 1373 | Models 1374 | sourceTree 1375 | <group> 1376 | 1377 | F3594B6D1D9B552D0046DA07 1378 | 1379 | fileEncoding 1380 | 4 1381 | isa 1382 | PBXFileReference 1383 | lastKnownFileType 1384 | sourcecode.swift 1385 | path 1386 | Note.swift 1387 | sourceTree 1388 | <group> 1389 | 1390 | F3594B6E1D9B552D0046DA07 1391 | 1392 | children 1393 | 1394 | F3594B6F1D9B552D0046DA07 1395 | F3594B701D9B552D0046DA07 1396 | F3594B711D9B552D0046DA07 1397 | 1398 | isa 1399 | PBXGroup 1400 | path 1401 | ViewControllers 1402 | sourceTree 1403 | <group> 1404 | 1405 | F3594B6F1D9B552D0046DA07 1406 | 1407 | fileEncoding 1408 | 4 1409 | isa 1410 | PBXFileReference 1411 | lastKnownFileType 1412 | sourcecode.swift 1413 | path 1414 | HomeViewController.swift 1415 | sourceTree 1416 | <group> 1417 | 1418 | F3594B701D9B552D0046DA07 1419 | 1420 | fileEncoding 1421 | 4 1422 | isa 1423 | PBXFileReference 1424 | lastKnownFileType 1425 | sourcecode.swift 1426 | path 1427 | LoginViewController.swift 1428 | sourceTree 1429 | <group> 1430 | 1431 | F3594B711D9B552D0046DA07 1432 | 1433 | fileEncoding 1434 | 4 1435 | isa 1436 | PBXFileReference 1437 | lastKnownFileType 1438 | sourcecode.swift 1439 | path 1440 | NoteViewController.swift 1441 | sourceTree 1442 | <group> 1443 | 1444 | F3594B721D9B552D0046DA07 1445 | 1446 | fileRef 1447 | F3594B671D9B552D0046DA07 1448 | isa 1449 | PBXBuildFile 1450 | 1451 | F3594B731D9B552D0046DA07 1452 | 1453 | fileRef 1454 | F3594B691D9B552D0046DA07 1455 | isa 1456 | PBXBuildFile 1457 | 1458 | F3594B741D9B552D0046DA07 1459 | 1460 | fileRef 1461 | F3594B6A1D9B552D0046DA07 1462 | isa 1463 | PBXBuildFile 1464 | 1465 | F3594B751D9B552D0046DA07 1466 | 1467 | fileRef 1468 | F3594B6B1D9B552D0046DA07 1469 | isa 1470 | PBXBuildFile 1471 | 1472 | F3594B761D9B552D0046DA07 1473 | 1474 | fileRef 1475 | F3594B6D1D9B552D0046DA07 1476 | isa 1477 | PBXBuildFile 1478 | 1479 | F3594B771D9B552D0046DA07 1480 | 1481 | fileRef 1482 | F3594B6F1D9B552D0046DA07 1483 | isa 1484 | PBXBuildFile 1485 | 1486 | F3594B781D9B552D0046DA07 1487 | 1488 | fileRef 1489 | F3594B701D9B552D0046DA07 1490 | isa 1491 | PBXBuildFile 1492 | 1493 | F3594B791D9B552D0046DA07 1494 | 1495 | fileRef 1496 | F3594B711D9B552D0046DA07 1497 | isa 1498 | PBXBuildFile 1499 | 1500 | F3594B7A1D9B55400046DA07 1501 | 1502 | children 1503 | 1504 | F3594B3F1D99FCC70046DA07 1505 | F3594B411D99FCC70046DA07 1506 | F3594B441D99FCC70046DA07 1507 | 1508 | isa 1509 | PBXGroup 1510 | name 1511 | Support 1512 | sourceTree 1513 | <group> 1514 | 1515 | 1516 | rootObject 1517 | F3594B2D1D99FCC70046DA07 1518 | 1519 | 1520 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/27/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | var window: UIWindow? 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 16 | return true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 38 | 44 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 154 | 155 | 156 | 157 | 163 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Config/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/27/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | let correctUsername = "appcoda" 10 | let correctPassword = "password" 11 | 12 | let notificationNewNoteCreated = "NewNoteCreated" 13 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Extensions/UIColor+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Extensions.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/28/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | class func colorWithRed(red: NSInteger, green: NSInteger, blue: NSInteger) -> UIColor { 13 | let max: CGFloat = 255.0 14 | return UIColor(red: CGFloat(red) / max, green: CGFloat(green) / max, blue: CGFloat(blue) / max, alpha: 1) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Extensions/UIStoryboard+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIStoryboard+Extensions.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/27/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIStoryboard { 12 | class func main() -> UIStoryboard { 13 | return UIStoryboard(name: "Main", bundle: nil) 14 | } 15 | 16 | class func initializeViewController(_ viewController: T.Type) -> T where T: UIViewController { 17 | return UIStoryboard.main().instantiateViewController(withIdentifier: String(describing: viewController)) as! T 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Extensions/UITableView+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+Extensions.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/27/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UITableView { 12 | func defaultCellWithReuseID(_ reuseID: String) -> UITableViewCell { 13 | return self.dequeueReusableCell(withIdentifier: reuseID) ?? UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: reuseID) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Extensions/UIViewController+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+Extensions.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/27/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIViewController { 12 | func showErrorAlertWithMessage(_ message: String) { 13 | let alertController = UIAlertController(title: "Error", message:message, preferredStyle: .alert) 14 | alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)) 15 | present(alertController, animated: true, completion: nil) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/Models/Note.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Note.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/27/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import RealmSwift 10 | 11 | class Note: Object { 12 | dynamic var title: String = "" 13 | dynamic var body: String = "" 14 | } 15 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/ViewControllers/HomeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HomeViewController.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/27/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RealmSwift 11 | 12 | class HomeViewController: UIViewController { 13 | @IBOutlet weak var emptyNotesLabel: UILabel! 14 | @IBOutlet weak var notesTableView: UITableView! 15 | 16 | var notes: Results? 17 | 18 | lazy var noteViewController : NoteViewController = { 19 | let viewController = UIStoryboard.initializeViewController(NoteViewController.self) 20 | let _ = viewController.view 21 | return viewController 22 | }() 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | NotificationCenter.default.addObserver(self, selector: #selector(HomeViewController.onNewNoteCreated), name: NSNotification.Name(rawValue: notificationNewNoteCreated), object: nil) 27 | } 28 | 29 | override func viewWillAppear(_ animated: Bool) { 30 | super.viewWillAppear(animated) 31 | updateNotes() 32 | } 33 | 34 | @IBAction func onTapAddNoteButton(_ sender: AnyObject) { 35 | noteViewController.note = nil 36 | navigationController?.pushViewController(noteViewController, animated: true) 37 | } 38 | 39 | func onNewNoteCreated() { 40 | updateTableViewVisibility() 41 | notesTableView.reloadData() 42 | } 43 | } 44 | 45 | extension HomeViewController { 46 | func updateNotes() { 47 | let realm = try! Realm() 48 | notes = realm.objects(Note.self) 49 | updateTableViewVisibility() 50 | notesTableView.reloadData() 51 | } 52 | 53 | func updateTableViewVisibility() { 54 | emptyNotesLabel.isHidden = (notes?.count)! > 0 55 | notesTableView.isHidden = !emptyNotesLabel.isHidden 56 | } 57 | } 58 | 59 | extension HomeViewController: UITableViewDataSource, UITableViewDelegate { 60 | func numberOfSections(in tableView: UITableView) -> Int { 61 | return 1 62 | } 63 | 64 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 65 | return notes?.count ?? 0 66 | } 67 | 68 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 69 | let cell = tableView.defaultCellWithReuseID("reuseID") 70 | let note = notes![indexPath.row] 71 | cell.textLabel?.text = note.title 72 | cell.detailTextLabel?.text = note.body 73 | return cell 74 | } 75 | 76 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 77 | tableView.deselectRow(at: indexPath, animated: true) 78 | noteViewController.note = notes![indexPath.row] 79 | navigationController?.pushViewController(noteViewController, animated: true) 80 | } 81 | 82 | func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 83 | return true 84 | } 85 | 86 | func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { 87 | if editingStyle == .delete { 88 | let realm = try! Realm() 89 | try! realm.write { 90 | realm.delete(notes![indexPath.row]) 91 | } 92 | tableView.beginUpdates() 93 | tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic) 94 | tableView.endUpdates() 95 | updateTableViewVisibility() 96 | } 97 | } 98 | 99 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 100 | return 60 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/ViewControllers/LoginViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/27/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class LoginViewController: UIViewController { 12 | @IBOutlet weak var usernameTextField: UITextField! 13 | @IBOutlet weak var passwordTextField: UITextField! 14 | 15 | lazy var homeViewController : HomeViewController = { 16 | let viewController = UIStoryboard.initializeViewController(HomeViewController.self) 17 | return viewController 18 | }() 19 | 20 | override func viewWillAppear(_ animated: Bool) { 21 | super.viewWillAppear(animated) 22 | navigationController?.setNavigationBarHidden(true, animated: false) 23 | } 24 | 25 | override func viewWillDisappear(_ animated: Bool) { 26 | super.viewWillDisappear(animated) 27 | navigationController?.setNavigationBarHidden(false, animated: false) 28 | } 29 | 30 | @IBAction func onTapLoginButton(_ sender: AnyObject) { 31 | guard let username = usernameTextField.text , username.characters.count > 0 else { 32 | showErrorAlertWithMessage("Username cannot be empty") 33 | return 34 | } 35 | guard let password = passwordTextField.text , password.characters.count > 0 else { 36 | showErrorAlertWithMessage("Password cannot be empty") 37 | return 38 | } 39 | guard username == correctUsername && password == correctPassword else { 40 | showErrorAlertWithMessage("Username or password is incorrect") 41 | return 42 | } 43 | navigationController?.pushViewController(homeViewController, animated: true) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /SimpleNoteTakingApp/ViewControllers/NoteViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteViewController.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/28/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RealmSwift 11 | fileprivate func < (lhs: T?, rhs: T?) -> Bool { 12 | switch (lhs, rhs) { 13 | case let (l?, r?): 14 | return l < r 15 | case (nil, _?): 16 | return true 17 | default: 18 | return false 19 | } 20 | } 21 | 22 | fileprivate func > (lhs: T?, rhs: T?) -> Bool { 23 | switch (lhs, rhs) { 24 | case let (l?, r?): 25 | return l > r 26 | default: 27 | return rhs < lhs 28 | } 29 | } 30 | 31 | 32 | class NoteViewController: UIViewController { 33 | var note: Note? { 34 | didSet { 35 | guard titleTextField != nil && bodyTextView != nil else { return } 36 | titleTextField.text = note?.title 37 | bodyTextView.text = note?.body 38 | navigationItem.rightBarButtonItem?.title = note != nil ? "Update" : "Create" 39 | onNoteTitleTextFieldChanged(titleTextField) 40 | } 41 | } 42 | 43 | @IBOutlet weak var titleTextField: UITextField! 44 | @IBOutlet weak var bodyTextView: UITextView! 45 | 46 | override func viewDidLoad() { 47 | super.viewDidLoad() 48 | setupNavigationButtons() 49 | setupBodyTextView() 50 | } 51 | 52 | func onTapCreateButton(_ sender: AnyObject) { 53 | _ = navigationController?.popViewController(animated: true) 54 | saveNoteToDatabase() 55 | NotificationCenter.default.post(name: Notification.Name(rawValue: notificationNewNoteCreated), object: nil) 56 | } 57 | 58 | func onTapCancelButton(_ sender: AnyObject) { 59 | _ = navigationController?.popViewController(animated: true) 60 | } 61 | 62 | @IBAction func onNoteTitleTextFieldChanged(_ sender: AnyObject) { 63 | navigationItem.rightBarButtonItem?.isEnabled = titleTextField.text?.characters.count > 0 64 | } 65 | } 66 | 67 | extension NoteViewController { 68 | fileprivate func setupNavigationButtons() { 69 | navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Create", style: .plain, target: self, action: #selector(NoteViewController.onTapCreateButton)) 70 | navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(NoteViewController.onTapCancelButton)) 71 | } 72 | 73 | fileprivate func setupBodyTextView() { 74 | bodyTextView.layer.borderWidth = 0.5 75 | bodyTextView.layer.borderColor = UIColor.colorWithRed(red: 204, green: 204, blue: 204).cgColor 76 | bodyTextView.layer.cornerRadius = 4; 77 | } 78 | 79 | fileprivate func saveNoteToDatabase() { 80 | let realm = try! Realm() 81 | try! realm.write { 82 | let note = self.note ?? Note() 83 | note.title = titleTextField.text! 84 | note.body = bodyTextView.text! 85 | realm.add(note) 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /SimpleNoteTakingAppTests/Extensions/KIF+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KIF+Extensions.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/28/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import KIF 10 | 11 | extension XCTestCase { 12 | func tester(_ file : String = #file, _ line : Int = #line) -> KIFUITestActor { 13 | return KIFUITestActor(inFile: file, atLine: line, delegate: self) 14 | } 15 | 16 | func system(_ file : String = #file, _ line : Int = #line) -> KIFSystemTestActor { 17 | return KIFSystemTestActor(inFile: file, atLine: line, delegate: self) 18 | } 19 | } 20 | 21 | extension KIFTestActor { 22 | func tester(_ file : String = #file, _ line : Int = #line) -> KIFUITestActor { 23 | return KIFUITestActor(inFile: file, atLine: line, delegate: self) 24 | } 25 | 26 | func system(_ file : String = #file, _ line : Int = #line) -> KIFSystemTestActor { 27 | return KIFSystemTestActor(inFile: file, atLine: line, delegate: self) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SimpleNoteTakingAppTests/Features/BaseUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseUITests.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/28/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | import KIF 10 | import Realm 11 | import RealmSwift 12 | 13 | class BaseUITests: KIFTestCase { 14 | override func beforeAll() { 15 | super.beforeAll() 16 | useTestDatabase() 17 | } 18 | 19 | override func beforeEach() { 20 | super.beforeEach() 21 | backToRoot() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SimpleNoteTakingAppTests/Features/HomeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteTests.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/28/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | class HomeTests: BaseUITests { 10 | 11 | override func beforeEach() { 12 | super.beforeEach() 13 | haveNoNotes() 14 | } 15 | 16 | func testNoNotes() { 17 | visitHomeScreen() 18 | expectToSeeLabel("No notes") 19 | expectNotToSeeNoteList() 20 | } 21 | 22 | func testCreateNewNote() { 23 | visitHomeScreen() 24 | tapButton("Add note") 25 | expectTheCreateButtonToBeDisabled() 26 | fillInNoteTitle("new note") 27 | expectTheCreateButtonToBeEnabled() 28 | fillInNoteBody("new body") 29 | tapButton("Create") 30 | expectToSeeNoteWithTitle("new note", body: "new body", atRow: 0) 31 | expectNumberOfNotesInListToEqual(1) 32 | } 33 | 34 | func testEditNote() { 35 | have3Notes() 36 | visitHomeScreen() 37 | tapOnNoteAtRow(1) 38 | updateNoteTitleTo("updated note") 39 | updateNoteBodyTo("updated body") 40 | tapButton("Update") 41 | expectToSeeNoteWithTitle("updated note", body: "updated body", atRow: 1) 42 | } 43 | 44 | func testDeleteNote() { 45 | have3Notes() 46 | visitHomeScreen() 47 | deleteANote() 48 | expectNumberOfNotesInListToEqual(2) 49 | deleteANote() 50 | expectNumberOfNotesInListToEqual(1) 51 | deleteANote() 52 | expectToSeeLabel("No notes") 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /SimpleNoteTakingAppTests/Features/LoginTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginTests.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/28/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | class LoginTests: BaseUITests { 10 | override func beforeEach() { 11 | super.beforeEach() 12 | clearOutUsernameAndPasswordFields() 13 | } 14 | 15 | func testEmptyUsername() { 16 | tapButton("Login") 17 | expectToSeeAlert("Username cannot be empty") 18 | tapButton("OK") 19 | } 20 | 21 | func testEmptyPassword() { 22 | fillInUsername() 23 | tapButton("Login") 24 | expectToSeeAlert("Password cannot be empty") 25 | tapButton("OK") 26 | } 27 | 28 | func testWrongUsernameOrPassword() { 29 | fillInUsername() 30 | fillInWrongPassword() 31 | tapButton("Login") 32 | expectToSeeAlert("Username or password is incorrect") 33 | tapButton("OK") 34 | } 35 | 36 | func testCorrectUsernameAndPassword() { 37 | fillInUsername() 38 | fillInCorrectPassword() 39 | tapButton("Login") 40 | expectToGoToHomeScreen() 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /SimpleNoteTakingAppTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /SimpleNoteTakingAppTests/SimpleNoteTakingAppTests-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import -------------------------------------------------------------------------------- /SimpleNoteTakingAppTests/Steps/CommonSteps.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommonSteps.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/28/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | @testable import SimpleNoteTakingApp 10 | import RealmSwift 11 | 12 | extension BaseUITests { 13 | func tapButton(_ buttonName: String) { 14 | tester().tapView(withAccessibilityLabel: buttonName) 15 | } 16 | 17 | func expectToSeeAlert(_ message: String) { 18 | expectToSee(message) 19 | } 20 | 21 | func fillIn(_ accessibilityLabel: String, withText text: String) { 22 | tester().clearText(fromAndThenEnterText: text, intoViewWithAccessibilityLabel: accessibilityLabel) 23 | } 24 | 25 | func backToRoot() { 26 | if let navigationController = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController { 27 | navigationController.popToRootViewController(animated: false) 28 | } 29 | } 30 | 31 | func fillInUsername() { 32 | fillIn("Login - Username", withText: correctUsername) 33 | } 34 | 35 | func visitHomeScreen() { 36 | fillInUsername() 37 | fillInCorrectPassword() 38 | tapButton("Login") 39 | } 40 | 41 | func fillInCorrectPassword() { 42 | fillIn("Login - Password", withText: correctPassword) 43 | } 44 | 45 | 46 | func useTestDatabase() { 47 | Realm.Configuration.defaultConfiguration.inMemoryIdentifier = name 48 | } 49 | 50 | func clearDatabase() { 51 | let realm = try! Realm() 52 | try! realm.write { 53 | realm.deleteAll() 54 | } 55 | } 56 | 57 | func expectToSee(_ text: String) { 58 | tester().waitForView(withAccessibilityLabel: text) 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /SimpleNoteTakingAppTests/Steps/HomeSteps.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteSteps.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/28/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | @testable import SimpleNoteTakingApp 10 | import RealmSwift 11 | import Nimble 12 | 13 | extension HomeTests { 14 | 15 | func haveNoNotes() { 16 | clearDatabase() 17 | } 18 | 19 | func expectTheCreateButtonToBeDisabled() { 20 | let createButton = tester().waitForView(withAccessibilityLabel: "Create") as! UIButton 21 | expect(createButton.isEnabled) == false 22 | } 23 | 24 | func expectTheCreateButtonToBeEnabled() { 25 | let createButton = tester().waitForView(withAccessibilityLabel: "Create") as! UIButton 26 | expect(createButton.isEnabled) == true 27 | } 28 | 29 | func expectNotToSeeNoteList() { 30 | tester().waitForAbsenceOfView(withAccessibilityLabel: "Note - Table View") 31 | } 32 | 33 | func expectToSeeNoteWithTitle(_ title: String, body: String, atRow row: NSInteger) { 34 | let noteCell = tester().waitForCell(at: IndexPath(row: row, section: 0), inTableViewWithAccessibilityIdentifier: "Note - TableView") 35 | expect(noteCell?.textLabel?.text) == title 36 | expect(noteCell?.detailTextLabel?.text) == body 37 | } 38 | 39 | func have3Notes() { 40 | let realm = try! Realm() 41 | try! realm.write { 42 | for i in 0...2 { 43 | let note = Note() 44 | note.title = "title \(i)" 45 | note.body = "body \(i)" 46 | realm.add(note) 47 | } 48 | } 49 | } 50 | 51 | func fillInNoteTitle(_ title: String) { 52 | fillIn("Note - Title", withText: title) 53 | } 54 | 55 | func fillInNoteBody(_ body: String) { 56 | fillIn("Note - Body", withText: body) 57 | } 58 | 59 | 60 | func updateNoteTitleTo(_ title: String) { 61 | fillInNoteTitle(title) 62 | } 63 | 64 | func updateNoteBodyTo(_ body: String) { 65 | fillInNoteBody(body) 66 | } 67 | 68 | func tapOnNoteAtRow(_ row: Int) { 69 | let indexPath = IndexPath(row: row, section: 0) 70 | tester().tapRow(at: indexPath, inTableViewWithAccessibilityIdentifier: "Note - TableView") 71 | } 72 | 73 | func expectNumberOfNotesInListToEqual(_ count: Int) { 74 | let noteTableView = tester().waitForView(withAccessibilityLabel: "Note - TableView") as! UITableView 75 | expect(noteTableView.numberOfRows(inSection: 0)) == count 76 | } 77 | 78 | func deleteANote() { 79 | let noteTableView = tester().waitForView(withAccessibilityLabel: "Note - TableView") as! UITableView 80 | tester().swipeRow(at: IndexPath(row: 0, section: 0), in: noteTableView, in: .left) 81 | tapButton("Delete") 82 | } 83 | 84 | func expectToSeeLabel(_ label: String) { 85 | expectToSee(label) 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /SimpleNoteTakingAppTests/Steps/LoginSteps.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginSteps.swift 3 | // SimpleNoteTakingApp 4 | // 5 | // Created by Hoang Tran on 9/28/16. 6 | // Copyright © 2016 AppCoda. All rights reserved. 7 | // 8 | 9 | extension LoginTests { 10 | func clearOutUsernameAndPasswordFields() { 11 | tester().clearTextFromView(withAccessibilityLabel: "Login - Username") 12 | tester().clearTextFromView(withAccessibilityLabel: "Login - Password") 13 | } 14 | 15 | func fillInWrongPassword() { 16 | fillIn("Login - Password", withText: "wrongPassword") 17 | } 18 | 19 | func expectToGoToHomeScreen() { 20 | tester().waitForAbsenceOfView(withAccessibilityLabel: "Login - Username") 21 | tester().waitForAbsenceOfView(withAccessibilityLabel: "Login - Password") 22 | tester().waitForAbsenceOfView(withAccessibilityLabel: "Login") 23 | tester().waitForView(withAccessibilityLabel: "No notes") 24 | tester().waitForView(withAccessibilityLabel: "Add note") 25 | } 26 | } 27 | --------------------------------------------------------------------------------