├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
├── images
│ ├── MSUITest-Coordinator-Flow.jpg
│ └── target_membership_aip.png
└── raw
│ └── MSUITest-Coordinator-Flow.xmind
├── .gitignore
├── .jazzy.yaml
├── .swiftlint.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Documentation
└── Advanced.md
├── Example
├── Examples.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Examples.xcscheme
├── Source
│ ├── Infrastructure
│ │ ├── Identifiable
│ │ │ └── Identifiable.swift
│ │ └── Routing
│ │ │ └── Coordinator.swift
│ ├── Main
│ │ ├── AppDelegate.swift
│ │ └── MainCoordinator
│ │ │ ├── MainCoordinator.swift
│ │ │ └── UITestCoordinator.swift
│ ├── Resources
│ │ └── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ └── minion.imageset
│ │ │ ├── 48659a38ae687fabe7fa101bf400d1ad.jpg
│ │ │ └── Contents.json
│ ├── Scenarios
│ │ ├── Button
│ │ │ ├── AIP
│ │ │ │ └── ButtonAIP.swift
│ │ │ ├── Coordinator
│ │ │ │ └── ButtonCoordinator.swift
│ │ │ └── View
│ │ │ │ ├── ButtonViewController.swift
│ │ │ │ └── ButtonViewController.xib
│ │ ├── Home
│ │ │ ├── AIP
│ │ │ │ └── HomeAIP.swift
│ │ │ ├── Coordinator
│ │ │ │ └── HomeCoordinator.swift
│ │ │ └── View
│ │ │ │ ├── HomeViewController.swift
│ │ │ │ └── HomeViewController.xib
│ │ ├── Image
│ │ │ ├── AIP
│ │ │ │ └── ImageAIP.swift
│ │ │ ├── Coordinator
│ │ │ │ └── ImageCoordinator.swift
│ │ │ └── View
│ │ │ │ ├── ImageViewController.swift
│ │ │ │ └── ImageViewController.xib
│ │ ├── Label
│ │ │ ├── AIP
│ │ │ │ └── LabelAIP.swift
│ │ │ ├── Coordinator
│ │ │ │ └── LabelCoordinator.swift
│ │ │ └── View
│ │ │ │ ├── LabelViewController.swift
│ │ │ │ └── LabelViewController.xib
│ │ ├── LaunchScreen
│ │ │ └── View
│ │ │ │ └── Base.lproj
│ │ │ │ └── LaunchScreen.storyboard
│ │ └── TextField
│ │ │ ├── AIP
│ │ │ └── TextFieldAIP.swift
│ │ │ ├── Coordinator
│ │ │ └── TextFieldCoordinator.swift
│ │ │ └── View
│ │ │ ├── TextFieldViewController.swift
│ │ │ └── TextFieldViewController.xib
│ └── SupportingFiles
│ │ └── Info.plist
└── Tests
│ └── UITests
│ ├── Info.plist
│ ├── PageObjects
│ ├── ButtonPage.swift
│ ├── HomePage.swift
│ ├── ImagePage.swift
│ ├── LabelPage.swift
│ └── TextFieldPage.swift
│ └── Scenario
│ ├── ButtonTests.swift
│ ├── HomeTests.swift
│ ├── ImageTests.swift
│ ├── LabelTests.swift
│ └── TextFieldTests.swift
├── LICENSE
├── MSUITest.podspec
├── MSUITest.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── MSUITest.xcscheme
├── MSUITest.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── README.md
├── Source
├── AIP
│ ├── Extensions
│ │ └── NSObject+Accessibility.swift
│ └── Provider
│ │ └── AccessibilityIdentifierProvider.swift
├── Core
│ ├── Extensions
│ │ ├── XCUIApplication+Lifecycle.swift
│ │ ├── XCUIElement+TextField.swift
│ │ └── XCUIElement+Timeout.swift
│ ├── LaunchArguments
│ │ └── UITestLaunchArguments.swift
│ └── PageObjects
│ │ ├── ElementProvider
│ │ └── PageObjectUIElementProvider.swift
│ │ ├── Helpers
│ │ └── HittableElementFinder.swift
│ │ ├── Models
│ │ └── SwipeAction.swift
│ │ ├── PageObject.swift
│ │ ├── PageObjectShould.swift
│ │ └── PageObjectWhen.swift
└── SupportingFiles
│ ├── Info.plist
│ └── MSUITest.h
└── docs
├── Enums.html
├── Enums
└── UITestLaunchArgument.html
├── Extensions.html
├── Extensions
├── UIAccessibilityIdentification.html
└── XCUIApplication.html
├── Protocols.html
├── Protocols
├── AccessibilityIdentifierProvider.html
├── PageObject.html
├── PageObjectShould.html
├── PageObjectUIElementProvider.html
└── PageObjectWhen.html
├── Structs.html
├── Structs
├── SwipeAction.html
└── SwipeAction
│ └── Direction.html
├── Typealiases.html
├── _config.yml
├── badge.svg
├── css
├── highlight.css
└── jazzy.css
├── docsets
├── MSUITest.docset
│ └── Contents
│ │ ├── Info.plist
│ │ └── Resources
│ │ ├── Documents
│ │ ├── Enums.html
│ │ ├── Enums
│ │ │ └── UITestLaunchArgument.html
│ │ ├── Extensions.html
│ │ ├── Extensions
│ │ │ ├── UIAccessibilityIdentification.html
│ │ │ └── XCUIApplication.html
│ │ ├── Protocols.html
│ │ ├── Protocols
│ │ │ ├── AccessibilityIdentifierProvider.html
│ │ │ ├── PageObject.html
│ │ │ ├── PageObjectShould.html
│ │ │ ├── PageObjectUIElementProvider.html
│ │ │ └── PageObjectWhen.html
│ │ ├── Structs.html
│ │ ├── Structs
│ │ │ ├── SwipeAction.html
│ │ │ └── SwipeAction
│ │ │ │ └── Direction.html
│ │ ├── Typealiases.html
│ │ ├── css
│ │ │ ├── highlight.css
│ │ │ └── jazzy.css
│ │ ├── img
│ │ │ ├── carat.png
│ │ │ ├── dash.png
│ │ │ ├── gh.png
│ │ │ └── spinner.gif
│ │ ├── index.html
│ │ ├── js
│ │ │ ├── jazzy.js
│ │ │ ├── jazzy.search.js
│ │ │ ├── jquery.min.js
│ │ │ ├── lunr.min.js
│ │ │ └── typeahead.jquery.js
│ │ └── search.json
│ │ └── docSet.dsidx
├── MSUITest.tgz
└── MSUITest.xml
├── img
├── carat.png
├── dash.png
├── gh.png
└── spinner.gif
├── index.html
├── js
├── jazzy.js
├── jazzy.search.js
├── jquery.min.js
├── lunr.min.js
└── typeahead.jquery.js
├── search.json
└── undocumented.json
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @MarcoSantarossa
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Version of the library affected
2 |
3 | ## *What* is affected by this bug
4 |
5 | ## *When* does this occur
6 |
7 | ## *How* do we replicate the issue
8 |
9 | ## Expected behavior (i.e. solution)
10 |
11 | ## Other Comments
12 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 |
4 | ## Motivation and Context
5 |
6 |
7 |
8 | ## Types of changes
9 |
10 | - [ ] Bug fix (non-breaking change which fixes an issue)
11 | - [ ] New feature (non-breaking change which adds functionality)
12 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
13 |
14 | # Checklist
15 |
16 |
17 | - [ ] My code follows the code style of this project.
18 | - [ ] My change requires a change to the documentation.
19 | - [ ] I have updated the documentation accordingly.
20 | - [ ] I have updated the changelog accordingly.
21 | - [ ] My change doesn't break the current UI tests
22 |
--------------------------------------------------------------------------------
/.github/images/MSUITest-Coordinator-Flow.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarcoSantarossa/MSUITest/30038418ee3baee0fe3d9075cc228f8a6da7cc7d/.github/images/MSUITest-Coordinator-Flow.jpg
--------------------------------------------------------------------------------
/.github/images/target_membership_aip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarcoSantarossa/MSUITest/30038418ee3baee0fe3d9075cc228f8a6da7cc7d/.github/images/target_membership_aip.png
--------------------------------------------------------------------------------
/.github/raw/MSUITest-Coordinator-Flow.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarcoSantarossa/MSUITest/30038418ee3baee0fe3d9075cc228f8a6da7cc7d/.github/raw/MSUITest-Coordinator-Flow.xmind
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | # Package.resolved
41 | .build/
--------------------------------------------------------------------------------
/.jazzy.yaml:
--------------------------------------------------------------------------------
1 | author: Marco Santarossa
2 | author_url: http://marcosantadev.com/
3 | github_url: https://github.com/MarcoSantarossa/MSUITest
4 | root_url: https://marcosantarossa.github.io/MSUITest/
5 | module: MSUITest
6 | output: docs
7 | theme: fullwidth
8 | xcodebuild_arguments: [-workspace, 'MSUITest.xcworkspace', -scheme, 'MSUITest']
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | opt_in_rules:
2 | - anyobject_protocol
3 | - array_init
4 | - attributes
5 | - closure_body_length
6 | - closure_end_indentation
7 | - closure_spacing
8 | - collection_alignment
9 | - contains_over_first_not_nil
10 | - empty_count
11 | - empty_string
12 | - empty_xctest_method
13 | - explicit_init
14 | - fallthrough
15 | - first_where
16 | - identical_operands
17 | - joined_default_parameter
18 | - let_var_whitespace
19 | - lower_acl_than_parent
20 | - last_where
21 | - legacy_random
22 | - modifier_order
23 | - operator_usage_whitespace
24 | - overridden_super_call
25 | - pattern_matching_keywords
26 | - private_action
27 | - private_outlet
28 | - prohibited_super_call
29 | - redundant_nil_coalescing
30 | - redundant_type_annotation
31 | - single_test_class
32 | - sorted_first_last
33 | - sorted_imports
34 | - static_operator
35 | - strong_iboutlet
36 | - unneeded_parentheses_in_closure_argument
37 | - untyped_error_in_catch
38 | - unused_import
39 | - unused_private_declaration
40 | - vertical_parameter_alignment_on_call
41 | - void_return
42 | - yoda_condition
43 |
44 |
45 | disabled_rules:
46 | - identifier_name
47 | - force_try
48 | - line_length
49 | - file_length
50 | - force_cast
51 | - function_body_length
52 | - type_body_length
53 | - xctfail_message
54 | - cyclomatic_complexity
55 |
56 | function_parameter_count: 7
57 |
58 | empty_count:
59 | severity: warning
60 |
61 | nesting:
62 | type_level:
63 | warning: 2
64 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [Unreleased]
9 |
10 | ### Added
11 |
12 | * [#28](https://github.com/MarcoSantarossa/MSUITest/pull/27) - Static jazzy website
13 | * [#27](https://github.com/MarcoSantarossa/MSUITest/pull/27) - Badges in readme
14 |
15 | ## [1.0.1] - 2019-07-21
16 |
17 | ### Added
18 |
19 | * [#25](https://github.com/MarcoSantarossa/MSUITest/pull/25) - New changelog
20 |
21 | ### Fixed
22 |
23 | * [#24](https://github.com/MarcoSantarossa/MSUITest/pull/24) - Podspec lint
24 |
25 | ## [1.0.0] - 2019-07-21
26 |
27 | ### Added
28 |
29 | * First Version of library
30 | * Documentation
31 |
32 | [Unreleased]: https://github.com/MarcoSantarossa/MSUITest/compare/v1.0.1...HEAD
33 | [1.0.1]: https://github.com/MarcoSantarossa/MSUITest/compare/v1.0.0...v1.0.1
34 | [1.0.0]: https://github.com/MarcoSantarossa/MSUITest/releases/tag/v1.0.0
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to MSUITest
2 |
3 | We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's:
4 |
5 | - Reporting a bug
6 | - Discussing the current state of the code
7 | - Submitting a fix
8 | - Proposing new features
9 | - Becoming a maintainer
10 |
11 | ## We Develop with Github
12 |
13 | We use github to host code, to track issues and feature requests, as well as accept pull requests.
14 |
15 | ## Any contributions you make will be under the MIT Software License
16 |
17 | In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern.
18 |
19 | ## Report bugs using Github's [issues](https://github.com/MarcoSantarossa/MSUITest/issues)
20 |
21 | We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/MarcoSantarossa/MSUITest/issues/new) and following the Issue template.
22 |
23 | ## Submit a change using Github's [pull request](https://github.com/MarcoSantarossa/MSUITest/pulls)
24 |
25 | We update the library using a pull request which allows the maintainer to review the changes and have an open discussion about it. [Create a new pull request](https://github.com/MarcoSantarossa/MSUITest/compare) and follow the PR template.
26 |
27 | ## License
28 |
29 | By contributing, you agree that your contributions will be licensed under its MIT License.
30 |
31 | [*Template reference*](https://gist.github.com/briandk/3d2e8b3ec8daf5a27a62)
32 |
--------------------------------------------------------------------------------
/Example/Examples.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Examples.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/Examples.xcodeproj/xcshareddata/xcschemes/Examples.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
85 |
91 |
92 |
93 |
94 |
96 |
97 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/Example/Source/Infrastructure/Identifiable/Identifiable.swift:
--------------------------------------------------------------------------------
1 | protocol Identifiable {
2 | static var identifier: String { get }
3 | }
4 |
--------------------------------------------------------------------------------
/Example/Source/Infrastructure/Routing/Coordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | protocol Coordinator: AnyObject, Identifiable {
24 | func start()
25 | }
26 |
27 | extension Coordinator {
28 | static var identifier: String {
29 | return String(describing: self)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Example/Source/Main/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 | import UIKit
25 |
26 | @UIApplicationMain
27 | class AppDelegate: UIResponder, UIApplicationDelegate {
28 |
29 | var window: UIWindow?
30 | private var mainCoordinator: Coordinator!
31 |
32 | func application(_ application: UIApplication,
33 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
34 |
35 | let window = UIWindow()
36 | let rootVC = UINavigationController()
37 | window.rootViewController = rootVC
38 | window.makeKeyAndVisible()
39 |
40 | self.window = window
41 |
42 | mainCoordinator = createMainCoordinator(with: rootVC)
43 | mainCoordinator.start()
44 |
45 | disableAnimationIfNeeded()
46 |
47 | return true
48 | }
49 |
50 | private func createMainCoordinator(with rootViewController: UINavigationController) -> Coordinator {
51 | if let coordinatorUnderUITest = UserDefaults.standard.string(forKey: "coordinatorUnderUITest") {
52 | return UITestCoordinator(rootViewController: rootViewController,
53 | coordinatorUnderUITest: coordinatorUnderUITest)
54 | } else {
55 | return MainCoordinator(rootViewController: rootViewController)
56 | }
57 | }
58 |
59 | private func disableAnimationIfNeeded() {
60 | guard UITestLaunchArgument.animationsDisabled.isActive else { return }
61 | UIView.setAnimationsEnabled(false)
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Example/Source/Main/MainCoordinator/MainCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | final class MainCoordinator: Coordinator {
26 |
27 | private var coords = [Coordinator]()
28 |
29 | private unowned let rootViewController: UINavigationController
30 |
31 | init(rootViewController: UINavigationController) {
32 | self.rootViewController = rootViewController
33 | }
34 |
35 | func start() {
36 | let homeCoord = HomeCoordinator(navigationController: rootViewController)
37 | homeCoord.start()
38 |
39 | coords.append(homeCoord)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Example/Source/Main/MainCoordinator/UITestCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | final class UITestCoordinator: Coordinator {
26 |
27 | private var coords = [Coordinator]()
28 |
29 | private unowned let rootViewController: UINavigationController
30 | private let coordinatorUnderUITest: String
31 |
32 | init(rootViewController: UINavigationController, coordinatorUnderUITest: String) {
33 | self.rootViewController = rootViewController
34 | self.coordinatorUnderUITest = coordinatorUnderUITest
35 | }
36 |
37 | func start() {
38 | let coordinator = createCoordinator()
39 | coordinator.start()
40 |
41 | coords.append(coordinator)
42 | }
43 |
44 | private func createCoordinator() -> Coordinator {
45 | switch coordinatorUnderUITest {
46 | case HomeCoordinator.identifier:
47 | return HomeCoordinator(navigationController: rootViewController)
48 | case LabelCoordinator.identifier:
49 | return LabelCoordinator(navigationController: rootViewController)
50 | case ButtonCoordinator.identifier:
51 | return ButtonCoordinator(navigationController: rootViewController)
52 | case TextFieldCoordinator.identifier:
53 | return TextFieldCoordinator(navigationController: rootViewController)
54 | case ImageCoordinator.identifier:
55 | return ImageCoordinator(navigationController: rootViewController)
56 | default:
57 | fatalError("Coordinator under UI tests not found")
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Example/Source/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Example/Source/Resources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/Source/Resources/Assets.xcassets/minion.imageset/48659a38ae687fabe7fa101bf400d1ad.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarcoSantarossa/MSUITest/30038418ee3baee0fe3d9075cc228f8a6da7cc7d/Example/Source/Resources/Assets.xcassets/minion.imageset/48659a38ae687fabe7fa101bf400d1ad.jpg
--------------------------------------------------------------------------------
/Example/Source/Resources/Assets.xcassets/minion.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "48659a38ae687fabe7fa101bf400d1ad.jpg",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Button/AIP/ButtonAIP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 |
25 | final class ButtonAIP: AIP {
26 | static var mainIdentifier: String = "button"
27 | }
28 |
29 | extension ButtonAIP {
30 | enum Element: String {
31 | case mainView
32 | case button
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Button/Coordinator/ButtonCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | final class ButtonCoordinator: Coordinator {
26 |
27 | private unowned let navigationController: UINavigationController
28 |
29 | init(navigationController: UINavigationController) {
30 | self.navigationController = navigationController
31 | }
32 |
33 | func start() {
34 | let view = ButtonViewController()
35 | navigationController.pushViewController(view, animated: true)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Button/View/ButtonViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | class ButtonViewController: UIViewController {
26 |
27 | @IBOutlet private var button: UIButton!
28 |
29 | override func viewDidLoad() {
30 | super.viewDidLoad()
31 |
32 | title = "Button"
33 |
34 | addAccessibility()
35 | }
36 |
37 | private func addAccessibility() {
38 | let aip = ButtonAIP.self
39 | view.addAccessibility(aip: aip, element: .mainView)
40 | button.addAccessibility(aip: aip, element: .button)
41 | }
42 |
43 | @IBAction private func onTap(_ sender: Any) {
44 | print("let's add something when I'm in easter egg mood 🤫")
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Button/View/ButtonViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Home/AIP/HomeAIP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 |
25 | final class HomeAIP: AIP {
26 | static var mainIdentifier: String = "home"
27 | }
28 |
29 | extension HomeAIP {
30 | enum Element: String {
31 | case mainView
32 | case tableView
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Home/Coordinator/HomeCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | final class HomeCoordinator: Coordinator {
26 |
27 | private unowned let navigationController: UINavigationController
28 |
29 | private var coords = [String: Coordinator]()
30 |
31 | init(navigationController: UINavigationController) {
32 | self.navigationController = navigationController
33 | }
34 |
35 | func start() {
36 | let onCellSeleted: (HomeCell) -> Void = { [weak self] in
37 | guard let self = self else { return }
38 | let coordinator = self.makeCoordinator(for: $0)
39 | coordinator.start()
40 | self.coords[type(of: coordinator).identifier] = coordinator
41 | }
42 |
43 | let view = HomeViewController(onCellSelected: onCellSeleted)
44 | navigationController.setViewControllers([view], animated: false)
45 | }
46 |
47 | private func makeCoordinator(for cell: HomeCell) -> Coordinator {
48 | switch cell {
49 | case .label:
50 | return LabelCoordinator(navigationController: navigationController)
51 | case .button:
52 | return ButtonCoordinator(navigationController: navigationController)
53 | case .textField:
54 | return TextFieldCoordinator(navigationController: navigationController)
55 | case .image:
56 | return ImageCoordinator(navigationController: navigationController)
57 | default:
58 | fatalError()
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Home/View/HomeViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | enum HomeCell: String, CaseIterable {
26 | case label
27 | case button
28 | case textField
29 | case image
30 | case alert
31 | }
32 |
33 | class HomeViewController: UIViewController {
34 |
35 | @IBOutlet private var tableView: UITableView!
36 |
37 | private let dataSource = HomeCell.allCases
38 | private let cellId = "HomeCell"
39 |
40 | private let onCellSelected: (HomeCell) -> Void
41 |
42 | init(onCellSelected: @escaping (HomeCell) -> Void) {
43 | self.onCellSelected = onCellSelected
44 |
45 | super.init(nibName: nil, bundle: nil)
46 | }
47 |
48 | required init?(coder aDecoder: NSCoder) {
49 | fatalError("init(coder:) has not been implemented")
50 | }
51 |
52 | override func viewDidLoad() {
53 | super.viewDidLoad()
54 |
55 | title = "Home"
56 |
57 | addAccessibility()
58 | }
59 |
60 | private func addAccessibility() {
61 | let aip = HomeAIP.self
62 | view.addAccessibility(aip: aip, element: .mainView)
63 | tableView.addAccessibility(aip: aip, element: .tableView)
64 | }
65 | }
66 |
67 | extension HomeViewController: UITableViewDataSource {
68 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
69 | return dataSource.count
70 | }
71 |
72 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
73 | let cell = tableView.dequeueReusableCell(withIdentifier: cellId) ??
74 | UITableViewCell(style: .default, reuseIdentifier: cellId)
75 |
76 | cell.textLabel?.text = dataSource[indexPath.row].rawValue
77 |
78 | return cell
79 | }
80 | }
81 |
82 | extension HomeViewController: UITableViewDelegate {
83 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
84 | let homeCell = dataSource[indexPath.row]
85 | if homeCell == .alert {
86 | showAlert()
87 | } else {
88 | onCellSelected(homeCell)
89 | }
90 |
91 | tableView.deselectRow(at: indexPath, animated: true)
92 | }
93 |
94 | private func showAlert() {
95 | let alertController = UIAlertController(title: "🚨 Alert 🚨",
96 | message: "[ Add here your test ]",
97 | preferredStyle: .alert)
98 | let cancelAction = UIAlertAction(title: "Close", style: .cancel)
99 | alertController.addAction(cancelAction)
100 |
101 | present(alertController, animated: true, completion: nil)
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Home/View/HomeViewController.xib:
--------------------------------------------------------------------------------
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 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Image/AIP/ImageAIP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 |
25 | final class ImageAIP: AIP {
26 | static var mainIdentifier: String = "image"
27 | }
28 |
29 | extension ImageAIP {
30 | enum Element: RawRepresentable {
31 | case mainView
32 | case imageView(_ imageName: String)
33 |
34 | init?(rawValue: String) {
35 | return nil
36 | }
37 |
38 | var rawValue: String {
39 | switch self {
40 | case .mainView:
41 | return "mainView"
42 | case .imageView(let name):
43 | return "imageView_image:\(name)"
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Image/Coordinator/ImageCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | final class ImageCoordinator: Coordinator {
26 |
27 | private unowned let navigationController: UINavigationController
28 |
29 | init(navigationController: UINavigationController) {
30 | self.navigationController = navigationController
31 | }
32 |
33 | func start() {
34 | let view = ImageViewController()
35 | navigationController.pushViewController(view, animated: true)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Image/View/ImageViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | class ImageViewController: UIViewController {
26 |
27 | @IBOutlet private var imageView: UIImageView!
28 |
29 | private let imageName: String = "minion"
30 |
31 | override func viewDidLoad() {
32 | super.viewDidLoad()
33 |
34 | title = "Image"
35 |
36 | imageView.image = UIImage(named: imageName)
37 |
38 | addAccessibility()
39 | }
40 |
41 | private func addAccessibility() {
42 | let aip = ImageAIP.self
43 | view.addAccessibility(aip: aip, element: .mainView)
44 | imageView.addAccessibility(aip: aip, element: .imageView(imageName))
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Image/View/ImageViewController.xib:
--------------------------------------------------------------------------------
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 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Label/AIP/LabelAIP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 |
25 | final class LabelAIP: AIP {
26 | static var mainIdentifier: String = "label"
27 | }
28 |
29 | extension LabelAIP {
30 | enum Element: String {
31 | case mainView
32 | case label
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Label/Coordinator/LabelCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | final class LabelCoordinator: Coordinator {
26 |
27 | private unowned let navigationController: UINavigationController
28 |
29 | init(navigationController: UINavigationController) {
30 | self.navigationController = navigationController
31 | }
32 |
33 | func start() {
34 | let view = LabelViewController()
35 | navigationController.pushViewController(view, animated: true)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Label/View/LabelViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | class LabelViewController: UIViewController {
26 |
27 | @IBOutlet private var label: UILabel!
28 |
29 | override func viewDidLoad() {
30 | super.viewDidLoad()
31 |
32 | title = "Label"
33 |
34 | addAccessibility()
35 | }
36 |
37 | private func addAccessibility() {
38 | let aip = LabelAIP.self
39 | view.addAccessibility(aip: aip, element: .mainView)
40 | label.addAccessibility(aip: aip, element: .label)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/Label/View/LabelViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/LaunchScreen/View/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 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/TextField/AIP/TextFieldAIP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 |
25 | final class TextFieldAIP: AIP {
26 | static var mainIdentifier: String = "textField"
27 | }
28 |
29 | extension TextFieldAIP {
30 | enum Element: String {
31 | case mainView
32 | case textField
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/TextField/Coordinator/TextFieldCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | final class TextFieldCoordinator: Coordinator {
26 |
27 | private unowned let navigationController: UINavigationController
28 |
29 | init(navigationController: UINavigationController) {
30 | self.navigationController = navigationController
31 | }
32 |
33 | func start() {
34 | let view = TextFieldViewController()
35 | navigationController.pushViewController(view, animated: true)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/TextField/View/TextFieldViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | class TextFieldViewController: UIViewController {
26 |
27 | @IBOutlet private var textField: UITextField!
28 |
29 | override func viewDidLoad() {
30 | super.viewDidLoad()
31 |
32 | title = "TextField"
33 |
34 | addAccessibility()
35 | }
36 |
37 | override func viewWillDisappear(_ animated: Bool) {
38 | super.viewWillDisappear(animated)
39 |
40 | textField.resignFirstResponder()
41 | }
42 |
43 | private func addAccessibility() {
44 | let aip = TextFieldAIP.self
45 | view.addAccessibility(aip: aip, element: .mainView)
46 | textField.addAccessibility(aip: aip, element: .textField)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Example/Source/Scenarios/TextField/View/TextFieldViewController.xib:
--------------------------------------------------------------------------------
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 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Example/Source/SupportingFiles/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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.1
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIRequiredDeviceCapabilities
26 |
27 | armv7
28 |
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/PageObjects/ButtonPage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 | import XCTest
25 |
26 | final class ButtonPage {
27 | typealias Element = ButtonAIP.Element
28 | }
29 |
30 | extension ButtonPage: PageObjectUIElementProvider, PageObject {
31 | func uiElement(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElement {
32 | let query = self.query(for: element, in: queryProvider)
33 |
34 | let identifier = ButtonAIP.elementIdentifier(for: element)
35 | return query[identifier]
36 | }
37 |
38 | private func query(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElementQuery {
39 | switch element {
40 | case .mainView:
41 | return queryProvider.otherElements
42 | case .button:
43 | return queryProvider.buttons
44 | }
45 | }
46 | }
47 |
48 | // MARK: - Given
49 | extension ButtonPage {
50 | func givenPage() -> ButtonPage {
51 | XCUIApplication().launchTestMode(customArguments: [
52 | "-coordinatorUnderUITest", "ButtonCoordinator"
53 | ])
54 |
55 | return self
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/PageObjects/HomePage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 | import XCTest
25 |
26 | final class HomePage {
27 | typealias Element = HomeAIP.Element
28 | }
29 |
30 | extension HomePage: PageObjectUIElementProvider, PageObject {
31 | func uiElement(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElement {
32 | let query = self.query(for: element, in: queryProvider)
33 |
34 | let identifier = HomeAIP.elementIdentifier(for: element)
35 | return query[identifier]
36 | }
37 |
38 | private func query(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElementQuery {
39 | switch element {
40 | case .mainView:
41 | return queryProvider.otherElements
42 | case .tableView:
43 | return queryProvider.tables
44 | }
45 | }
46 | }
47 |
48 | // MARK: - Given
49 | extension HomePage {
50 | func givenPage() -> HomePage {
51 | XCUIApplication().launchTestMode(customArguments: [
52 | "-coordinatorUnderUITest", "HomeCoordinator"
53 | ])
54 |
55 | return self
56 | }
57 | }
58 |
59 | // MARK: - When
60 | extension HomePage {
61 | func whenFocusTextField() -> HomePage {
62 | TextFieldPage()
63 | .whenTap(element: .textField)
64 |
65 | return self
66 | }
67 | }
68 |
69 | // MARK: - Should
70 | extension HomePage {
71 | @discardableResult
72 | func shouldSeeLabelPage() -> HomePage {
73 |
74 | LabelPage()
75 | .thenIShouldSee(element: .mainView)
76 |
77 | return self
78 | }
79 |
80 | @discardableResult
81 | func shouldSeeButtonPage() -> HomePage {
82 |
83 | ButtonPage()
84 | .thenIShouldSee(element: .mainView)
85 |
86 | return self
87 | }
88 |
89 | @discardableResult
90 | func shouldSeeTextFieldPage() -> HomePage {
91 |
92 | TextFieldPage()
93 | .thenIShouldSee(element: .mainView)
94 |
95 | return self
96 | }
97 |
98 | @discardableResult
99 | func shouldSeeImagePage() -> HomePage {
100 |
101 | ImagePage()
102 | .thenIShouldSee(element: .mainView)
103 |
104 | return self
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/PageObjects/ImagePage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 | import XCTest
25 |
26 | final class ImagePage {
27 | typealias Element = ImageAIP.Element
28 | }
29 |
30 | extension ImagePage: PageObjectUIElementProvider, PageObject {
31 | func uiElement(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElement {
32 | let query = self.query(for: element, in: queryProvider)
33 |
34 | let identifier = ImageAIP.elementIdentifier(for: element)
35 | return query[identifier]
36 | }
37 |
38 | private func query(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElementQuery {
39 | switch element {
40 | case .mainView:
41 | return queryProvider.otherElements
42 | case .imageView:
43 | return queryProvider.images
44 | }
45 | }
46 | }
47 |
48 | // MARK: - Given
49 | extension ImagePage {
50 | func givenPage() -> ImagePage {
51 | XCUIApplication().launchTestMode(customArguments: [
52 | "-coordinatorUnderUITest", "ImageCoordinator"
53 | ])
54 |
55 | return self
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/PageObjects/LabelPage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 | import XCTest
25 |
26 | final class LabelPage {
27 | typealias Element = LabelAIP.Element
28 | }
29 |
30 | extension LabelPage: PageObjectUIElementProvider, PageObject {
31 | func uiElement(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElement {
32 | let query = self.query(for: element, in: queryProvider)
33 |
34 | let identifier = LabelAIP.elementIdentifier(for: element)
35 | return query[identifier]
36 | }
37 |
38 | private func query(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElementQuery {
39 | switch element {
40 | case .mainView:
41 | return queryProvider.otherElements
42 | case .label:
43 | return queryProvider.staticTexts
44 | }
45 | }
46 | }
47 |
48 | // MARK: - Given
49 | extension LabelPage {
50 | func givenPage() -> LabelPage {
51 | XCUIApplication().launchTestMode(customArguments: [
52 | "-coordinatorUnderUITest", "LabelCoordinator"
53 | ])
54 |
55 | return self
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/PageObjects/TextFieldPage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import MSUITest
24 | import XCTest
25 |
26 | final class TextFieldPage {
27 | typealias Element = TextFieldAIP.Element
28 | }
29 |
30 | extension TextFieldPage: PageObjectUIElementProvider, PageObject {
31 | func uiElement(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElement {
32 | let query = self.query(for: element, in: queryProvider)
33 |
34 | let identifier = TextFieldAIP.elementIdentifier(for: element)
35 | return query[identifier]
36 | }
37 |
38 | private func query(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElementQuery {
39 | switch element {
40 | case .mainView:
41 | return queryProvider.otherElements
42 | case .textField:
43 | return queryProvider.textFields
44 | }
45 | }
46 | }
47 |
48 | // MARK: - Given
49 | extension TextFieldPage {
50 | func givenPage() -> TextFieldPage {
51 | XCUIApplication().launchTestMode(customArguments: [
52 | "-coordinatorUnderUITest", "TextFieldCoordinator"
53 | ])
54 |
55 | return self
56 | }
57 | }
58 |
59 | // MARK: - Then
60 | extension TextFieldPage {
61 | @discardableResult
62 | func thenIShouldSeeEmptyTextFieldWithPlaceholder() -> TextFieldPage {
63 | if #available(iOS 11.0, *) {
64 | return thenIShouldSee(element: .textField, text: "Try me 🤓")
65 | } else {
66 | return thenIShouldSee(element: .textField, text: "")
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/Scenario/ButtonTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | class ButtonTests: XCTestCase {
26 |
27 | func test_whenLoadView_seeExpectedElements() {
28 | ButtonPage()
29 | .givenPage()
30 |
31 | .thenIShouldSee(element: .mainView, timeout: 0.3)
32 | .thenIShouldSeeNavigationBar(text: "Button")
33 | .thenIShouldSee(element: .button, text: "Yes, I'm a button")
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/Scenario/HomeTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | class HomeTests: XCTestCase {
26 |
27 | func test_whenLoadView_seeExpectedElements() {
28 | HomePage()
29 | .givenPage()
30 |
31 | .thenIShouldSee(element: .mainView, timeout: 0.3)
32 | .thenIShouldSeeNavigationBar(text: "Home")
33 | .thenIShouldSee(element: .tableView)
34 | .thenIShouldSee(in: .tableView, at: 0, text: "label")
35 | .thenIShouldSee(in: .tableView, at: 1, text: "button")
36 | .thenIShouldSee(in: .tableView, at: 2, text: "textField")
37 | .thenIShouldSee(in: .tableView, at: 3, text: "image")
38 | .thenIShouldSee(in: .tableView, at: 4, text: "alert")
39 | }
40 |
41 | func test_whenTapLabelCell_seeLabelView() {
42 | HomePage()
43 | .givenPage()
44 |
45 | .whenTapCell(in: .tableView, at: 0)
46 |
47 | .shouldSeeLabelPage()
48 | }
49 |
50 | func test_whenTapLabelCellAndBackButton_seeMainView() {
51 | HomePage()
52 | .givenPage()
53 |
54 | .whenTapCell(in: .tableView, at: 0)
55 | .whenTapBackButton()
56 |
57 | .thenIShouldSee(element: .mainView)
58 | }
59 |
60 | func test_whenTapButtonCell_seeButtonView() {
61 | HomePage()
62 | .givenPage()
63 |
64 | .whenTapCell(in: .tableView, at: 1)
65 |
66 | .shouldSeeButtonPage()
67 | }
68 |
69 | func test_whenTapButtonCellAndBackButton_seeMainView() {
70 | HomePage()
71 | .givenPage()
72 |
73 | .whenTapCell(in: .tableView, at: 1)
74 | .whenTapBackButton()
75 |
76 | .thenIShouldSee(element: .mainView)
77 | }
78 |
79 | func test_whenTapTextFieldCell_seeTextFieldView() {
80 | HomePage()
81 | .givenPage()
82 |
83 | .whenTapCell(in: .tableView, at: 2)
84 |
85 | .shouldSeeTextFieldPage()
86 | }
87 |
88 | func test_whenTapTextFieldCellAndBackButton_seeMainView() {
89 | HomePage()
90 | .givenPage()
91 |
92 | .whenTapCell(in: .tableView, at: 2)
93 | .whenTapBackButton()
94 |
95 | .thenIShouldSee(element: .mainView)
96 | }
97 |
98 | func test_whenTapTextFieldCellAndFocusAndBackButton_doNotSeeKeyboard() {
99 | HomePage()
100 | .givenPage()
101 |
102 | .whenTapCell(in: .tableView, at: 2)
103 | .whenFocusTextField()
104 |
105 | .delay(0.2)
106 |
107 | .whenTapBackButton()
108 |
109 | .thenIShouldNotSeeKeyboard()
110 | }
111 |
112 | func test_whenTapImageCell_seeImageView() {
113 | HomePage()
114 | .givenPage()
115 |
116 | .whenTapCell(in: .tableView, at: 3)
117 |
118 | .shouldSeeImagePage()
119 | }
120 |
121 | func test_whenTapImageCellAndBackButton_seeMainView() {
122 | HomePage()
123 | .givenPage()
124 |
125 | .whenTapCell(in: .tableView, at: 3)
126 | .whenTapBackButton()
127 |
128 | .thenIShouldSee(element: .mainView)
129 | }
130 |
131 | func test_whenTapAlertCell_seeAlert() {
132 | HomePage()
133 | .givenPage()
134 |
135 | .whenTapCell(in: .tableView, at: 4)
136 |
137 | .thenIShouldSeeAlert(title: "🚨 Alert 🚨", message: "[ Add here your test ]")
138 | }
139 |
140 | func test_whenTapAlertCellAndTapCancel_doNotSeeAlert() {
141 | HomePage()
142 | .givenPage()
143 |
144 | .whenTapCell(in: .tableView, at: 4)
145 | .whenTapAlertButton(at: 0)
146 |
147 | .thenIShouldNotSeeAlert()
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/Scenario/ImageTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | class ImageTests: XCTestCase {
26 |
27 | func test_whenLoadView_seeExpectedElements() {
28 | ImagePage()
29 | .givenPage()
30 |
31 | .thenIShouldSee(element: .mainView, timeout: 0.3)
32 | .thenIShouldSeeNavigationBar(text: "Image")
33 | .thenIShouldSee(element: .imageView("minion"))
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/Scenario/LabelTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | class LabelTests: XCTestCase {
26 |
27 | func test_whenLoadView_seeExpectedElements() {
28 | LabelPage()
29 | .givenPage()
30 |
31 | .thenIShouldSee(element: .mainView, timeout: 0.3)
32 | .thenIShouldSeeNavigationBar(text: "Label")
33 | .thenIShouldSee(element: .label, text: "Welcome ✌🏻")
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Example/Tests/UITests/Scenario/TextFieldTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | class TextFieldTests: XCTestCase {
26 |
27 | func test_whenLoadView_seeExpectedElements() {
28 | TextFieldPage()
29 | .givenPage()
30 |
31 | .thenIShouldSee(element: .mainView, timeout: 0.3)
32 | .thenIShouldSeeNavigationBar(text: "TextField")
33 | .thenIShouldSeeEmptyTextFieldWithPlaceholder()
34 | }
35 |
36 | func test_whenTapTextField_seeKeyboard() {
37 | TextFieldPage()
38 | .givenPage()
39 |
40 | .whenTap(element: .textField)
41 |
42 | .thenIShouldSeeKeyboard()
43 | }
44 |
45 | func test_whenTypeOnTextField_doNotSeePlaceholder() {
46 | TextFieldPage()
47 | .givenPage()
48 |
49 | .whenType("a", in: .textField)
50 |
51 | .thenIShouldSee(element: .textField, text: "a")
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Marco Santarossa
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MSUITest.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 |
3 | spec.name = "MSUITest"
4 | spec.version = "1.0.1"
5 | spec.summary = "A Swift XCUITest wrapper inspired by Gherkin syntax."
6 |
7 | spec.description = <<-DESC
8 | A XCUITest wrapper written in Swift inspired by the Gherkin syntax to allow everyone to write human readable UI tests in a clean way.
9 | DESC
10 |
11 | spec.homepage = "https://github.com/MarcoSantarossa/MSUITest"
12 |
13 | spec.license = { :type => "MIT", :file => "LICENSE" }
14 |
15 | spec.author = "Marco Santarossa"
16 | spec.social_media_url = "https://twitter.com/MarcoSantaDev"
17 |
18 | spec.source = { :git => "https://github.com/MarcoSantarossa/MSUITest.git", :tag => "v#{spec.version}" }
19 |
20 | spec.swift_version = '5.0'
21 | spec.platform = :ios, '10.0'
22 |
23 | spec.subspec "Core" do |ss|
24 | ss.source_files = "Source/Core/**/*.swift"
25 | ss.framework = "XCTest"
26 | end
27 |
28 | spec.subspec "App" do |ss|
29 | ss.source_files = ["Source/AIP/**/*.swift", "Source/Core/LaunchArguments/UITestLaunchArguments.swift"]
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/MSUITest.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MSUITest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MSUITest.xcodeproj/xcshareddata/xcschemes/MSUITest.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/MSUITest.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/MSUITest.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Source/AIP/Extensions/NSObject+Accessibility.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | extension UIAccessibilityIdentification where Self: NSObject {
26 | /// Add an accessibility identifier to a UIKit element.
27 | ///
28 | /// - Parameters:
29 | /// - aip: AIP to provide the Element.
30 | /// - element: Element of AIP to assign to the UIKit element.
31 | public func addAccessibility(aip: T.Type, element: T.Element) {
32 | let id = T.elementIdentifier(for: element)
33 | accessibilityIdentifier = id
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Source/AIP/Provider/AccessibilityIdentifierProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import Foundation
24 |
25 | /// Type alias of AccessibilityIdentifierProvider to use as shorter name alternative.
26 | public typealias AIP = AccessibilityIdentifierProvider
27 |
28 | /**
29 | This object handles the identifer of the UI elements to test.
30 |
31 |
32 | Example:
33 | ````
34 | final class HomeAIP: AIP {
35 | static var mainIdentifier: String = "home"
36 | }
37 |
38 | extension HomeAIP {
39 | enum Element: String {
40 | case mainView
41 | case tableView
42 | }
43 | }
44 |
45 | ````
46 | */
47 | public protocol AccessibilityIdentifierProvider: AnyObject {
48 | associatedtype Element
49 |
50 | /// The name of a specific container of UI elements. It could be a good idea using the name of the view of the UI elements like "home".
51 | static var mainIdentifier: String { get }
52 |
53 | /// Helper method to provide the complete identifier of an UI element. You don't need to implement it. An internal extension provides the expected behaviour.
54 | ///
55 | /// - Parameter element: UI Element which needs an identifier.
56 | /// - Returns: The complete identifier of the UI element.
57 | static func elementIdentifier(for element: Element) -> String
58 | }
59 |
60 | extension AccessibilityIdentifierProvider where Element: RawRepresentable, Element.RawValue == String {
61 | public static func elementIdentifier(for element: Element) -> String {
62 | return mainIdentifier + "." + element.rawValue
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Source/Core/Extensions/XCUIApplication+Lifecycle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | extension XCUIApplication {
26 | /// Launches a UI test with specific arguments.
27 | ///
28 | /// It sets some arguments by default. See the README.md for more details.
29 | ///
30 | /// - Parameter customArguments: Custom arguments to add.
31 | public func launchTestMode(customArguments: [String]? = nil) {
32 | let hiddenArgs = [
33 | "-FIRDebugDisabled"
34 | ]
35 | let defaultArgs: [String] = UITestLaunchArgument.allCases.flatMap {
36 | return ["-\($0.rawValue)", "1"]
37 | }
38 | var args = hiddenArgs + defaultArgs
39 | if let customArguments = customArguments {
40 | args.append(contentsOf: customArguments)
41 | }
42 | launchArguments = args
43 |
44 | launch()
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Source/Core/Extensions/XCUIElement+TextField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | extension XCUIElement {
26 | func clearTextIfNeeded() {
27 | guard let stringValue = self.value as? String else {
28 | return
29 | }
30 |
31 | let deleteString: String = stringValue.lazy.map { _ in XCUIKeyboardKey.delete.rawValue }.joined()
32 | typeText(deleteString)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Source/Core/Extensions/XCUIElement+Timeout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | extension XCUIElement {
26 | func waitIfNeeded(timeout: TimeInterval?) {
27 | guard let timeout = timeout else { return }
28 | _ = waitForExistence(timeout: timeout)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Source/Core/LaunchArguments/UITestLaunchArguments.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import Foundation
24 |
25 | /// List of internal launch arguments used from MSUITest and available for the client.
26 | public enum UITestLaunchArgument: String, CaseIterable {
27 | /// Request to disable the animation. Animations can create flicky tests.
28 | case animationsDisabled
29 |
30 | /**
31 | Checks if a launch argument has been set from MSUITest.
32 |
33 | Example:
34 | ````
35 | guard UITestLaunchArgument.animationsDisabled.isActive else { return }
36 | UIView.setAnimationsEnabled(false)
37 | ````
38 | */
39 | public var isActive: Bool {
40 | return UserDefaults.standard.object(forKey: self.rawValue) != nil
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Source/Core/PageObjects/ElementProvider/PageObjectUIElementProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | /** Abstract object to provide a XCUIElement given a specific AIP element.
26 |
27 | Example:
28 | ````
29 | extension HomePage: PageObjectUIElementProvider, PageObject {
30 | func uiElement(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElement {
31 | let query = self.query(for: element, in: queryProvider)
32 |
33 | let identifier = HomeAIP.elementIdentifier(for: element)
34 | return query[identifier]
35 | }
36 |
37 | private func query(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElementQuery {
38 | switch element {
39 | case .mainView:
40 | return queryProvider.otherElements
41 | case .tableView:
42 | return queryProvider.tables
43 | }
44 | }
45 |
46 | ````
47 | */
48 | public protocol PageObjectUIElementProvider: AnyObject {
49 | associatedtype Element
50 |
51 | /// Method to provide a XCUIElement given a specific AIP element.
52 | ///
53 | /// - Parameters:
54 | /// - element: AIP element to convert.
55 | /// - queryProvider: Provider where to find the XCUIElement element. Default: XCUIApplication().
56 | /// - Returns: the XCUIElement found.
57 | func uiElement(for element: Element, in queryProvider: XCUIElementTypeQueryProvider) -> XCUIElement
58 | }
59 |
--------------------------------------------------------------------------------
/Source/Core/PageObjects/Helpers/HittableElementFinder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | final class HittableElementFinder {
26 | static func findSwipingIfNeeded(element: XCUIElement, swipeAction: SwipeAction?) {
27 | guard let swipeAction = swipeAction else { return }
28 | var numSwipes = 0
29 | while (!element.exists || element.frame.isEmpty || !element.isHittable) && numSwipes < swipeAction.maxSwipes {
30 | switch swipeAction.direction {
31 | case .up:
32 | swipeAction.target.swipeUp()
33 | case .down:
34 | swipeAction.target.swipeDown()
35 | case .left:
36 | swipeAction.target.swipeLeft()
37 | case .right:
38 | swipeAction.target.swipeRight()
39 | }
40 |
41 | numSwipes += 1
42 | }
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/Source/Core/PageObjects/Models/SwipeAction.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | /// Paylod object to perform a swipe action.
26 | public struct SwipeAction {
27 | /// Where to perform the swipe.
28 | let target: XCUIElement
29 |
30 | /// The direction of the swipe.
31 | let direction: Direction
32 |
33 | /// Limit of swipes before stopping.
34 | let maxSwipes: Int
35 | }
36 |
37 | extension SwipeAction {
38 | public enum Direction {
39 | case up
40 | case right
41 | case down
42 | case left
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Source/Core/PageObjects/PageObject.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | import XCTest
24 |
25 | /// Abstract Page object to provide the default functionality for a concrete Page object.
26 | /// * Attention: **None** of these methods require a custom implementation. Everything is provided with internal extensions.
27 | public protocol PageObject: PageObjectWhen, PageObjectShould {
28 |
29 | /// Add a delay before continuing with the UI test flow.
30 | ///
31 | /// - Parameter delay: Seconds to add as delay
32 | /// - Returns: itself to use in a chain of calls.
33 | @discardableResult
34 | func delay(_ delay: TimeInterval) -> Self
35 |
36 | /// Terminates an UI test
37 | static func terminate()
38 | }
39 |
40 | extension PageObject {
41 | @discardableResult
42 | public func delay(_ delay: TimeInterval) -> Self {
43 | Thread.sleep(forTimeInterval: delay)
44 |
45 | return self
46 | }
47 | }
48 |
49 | extension PageObject {
50 | public static func terminate() {
51 | XCUIApplication().terminate()
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Source/SupportingFiles/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.1
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Source/SupportingFiles/MSUITest.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Marco Santarossa
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | #import
24 |
25 | //! Project version number for MSUITest.
26 | FOUNDATION_EXPORT double MSUITestVersionNumber;
27 |
28 | //! Project version string for MSUITest.
29 | FOUNDATION_EXPORT const unsigned char MSUITestVersionString[];
30 |
31 | // In this header, you should import all the public headers of your framework using statements like #import
32 |
33 |
34 |
--------------------------------------------------------------------------------
/docs/Enums.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Enumerations Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |