diff --git a/.travis.yml b/.travis.yml
index 2b3cf18..e7141cc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,21 +20,21 @@ env:
- EXAMPLE_SCHEME="IGListKitExamples"
matrix:
- - DESTINATION="OS=8.1,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="YES" POD_LINT="YES"
- - DESTINATION="OS=8.2,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO"
- - DESTINATION="OS=8.3,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO"
- - DESTINATION="OS=8.4,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO"
+ - DESTINATION="OS=8.1,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="YES" RUN_UI_TESTS="NO" POD_LINT="YES"
+ - DESTINATION="OS=8.2,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" RUN_UI_TESTS="NO" POD_LINT="NO"
+ - DESTINATION="OS=8.3,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" RUN_UI_TESTS="NO" POD_LINT="NO"
+ - DESTINATION="OS=8.4,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" RUN_UI_TESTS="NO" POD_LINT="NO"
- - DESTINATION="OS=9.0,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="YES"
- - DESTINATION="OS=9.1,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO"
- - DESTINATION="OS=9.2,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO"
- - DESTINATION="OS=9.3,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO"
+ - DESTINATION="OS=9.0,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" RUN_UI_TESTS="NO" POD_LINT="YES"
+ - DESTINATION="OS=9.1,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" RUN_UI_TESTS="NO" POD_LINT="NO"
+ - DESTINATION="OS=9.2,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" RUN_UI_TESTS="NO" POD_LINT="NO"
+ - DESTINATION="OS=9.3,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" RUN_UI_TESTS="NO" POD_LINT="NO"
- - DESTINATION="OS=10.0,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO"
- - DESTINATION="OS=10.1,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO"
+ - DESTINATION="OS=10.0,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" RUN_UI_TESTS="YES" POD_LINT="NO"
+ - DESTINATION="OS=10.1,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" RUN_UI_TESTS="NO" POD_LINT="NO"
- - DESTINATION="OS=9.0,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="YES"
- - DESTINATION="OS=10.0,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO"
+ - DESTINATION="OS=9.0,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" RUN_UI_TESTS="NO" POD_LINT="YES"
+ - DESTINATION="OS=10.0,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" RUN_UI_TESTS="NO" POD_LINT="NO"
before_install:
- gem install slather --no-rdoc --no-ri --no-document --quiet
@@ -49,6 +49,10 @@ script:
xcodebuild build -workspace Examples/Examples-iOS/"$EXAMPLE_WORKSPACE" -scheme "$EXAMPLE_SCHEME" -sdk "$SDK" -destination "$DESTINATION" ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO | xcpretty -c;
fi
+- if [ $RUN_UI_TESTS == "YES" ] && [ $SDK == $IOS_SDK ]; then
+ xcodebuild analyze test -workspace Examples/Examples-iOS/"$EXAMPLE_WORKSPACE" -scheme "$EXAMPLE_SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO | xcpretty -c;
+ fi
+
- if [ $BUILD_EXAMPLE == "YES" ] && [ $SDK == $TVOS_SDK ]; then
xcodebuild build -workspace Examples/Examples-tvOS/"$EXAMPLE_WORKSPACE" -scheme "$EXAMPLE_SCHEME" -sdk "$SDK" -destination "$DESTINATION" ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO | xcpretty -c;
diff --git a/Examples/Examples-iOS/IGListKitExamples-UITests/DemosViewControllerUITests.swift b/Examples/Examples-iOS/IGListKitExamples-UITests/DemosViewControllerUITests.swift
new file mode 100644
index 0000000..49a557d
--- /dev/null
+++ b/Examples/Examples-iOS/IGListKitExamples-UITests/DemosViewControllerUITests.swift
@@ -0,0 +1,82 @@
+/**
+ Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
+
+ The examples provided by Facebook are for non-commercial testing and evaluation
+ purposes only. Facebook reserves all rights not expressly granted.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+import XCTest
+
+final class DemosViewControllerUITests: UITestCase {
+
+ func test_whenSelectingTailLoading_thatTailLoadingDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Tail Loading")
+ }
+
+ func test_whenSelectingSearchAutocomplete_thatSearchAutocompleteDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Search Autocomplete")
+ }
+
+ func test_whenSelectingMixedData_thatMixedDataDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Mixed Data")
+ }
+
+ func test_whenSelectingNestedAdapter_thatNestedAdapterDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Nested Adapter")
+ }
+
+ func test_whenSelectingEmptyView_thatEmptyViewDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Empty View")
+ }
+
+ func test_whenSelectingSingleSectionController_thatSingleSectionControllerScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Single Section Controller")
+ }
+
+ func test_whenSelectingStoryboard_thatStoryboardDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Storyboard")
+ }
+
+ func test_whenSelectingSingleSectionStoryboard_thatSingleSectionStoryboardDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Single Section Storyboard")
+ }
+
+ func test_whenSelectingWorkingRange_thatWorkingRangeDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Working Range")
+ }
+
+ func test_whenSelectingDiffAlgorithm_thatDiffAlgorithmDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Diff Algorithm")
+ }
+
+ func test_whenSelectingSupplementaryViews_thatSupplementaryViewsDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Supplementary Views")
+ }
+
+ func test_whenSelectingSelfSizingCells_thatSelfSizingCellsDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Self-sizing cells")
+ }
+
+ func test_whenSelectingDisplayDelegate_thatDisplayDelegateDetailScreenIsPresented() {
+ enterAndAssertScreen(withTitle: "Display delegate")
+ }
+
+
+ private func enterAndAssertScreen(withTitle title: String) {
+ let elem = app.collectionViews.cells.staticTexts[title]
+ if !elem.exists {
+ app.collectionViews.element.swipeUp()
+ }
+
+ XCTAssertTrue(elem.exists)
+ elem.tap()
+ XCTAssertTrue(app.navigationBars[title].exists)
+ }
+}
diff --git a/Examples/Examples-iOS/IGListKitExamples-UITests/Info.plist b/Examples/Examples-iOS/IGListKitExamples-UITests/Info.plist
new file mode 100644
index 0000000..6c6c23c
--- /dev/null
+++ b/Examples/Examples-iOS/IGListKitExamples-UITests/Info.plist
@@ -0,0 +1,22 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+
+
diff --git a/Examples/Examples-iOS/IGListKitExamples-UITests/LoadMoreViewControllerUITests.swift b/Examples/Examples-iOS/IGListKitExamples-UITests/LoadMoreViewControllerUITests.swift
new file mode 100644
index 0000000..b6e423d
--- /dev/null
+++ b/Examples/Examples-iOS/IGListKitExamples-UITests/LoadMoreViewControllerUITests.swift
@@ -0,0 +1,34 @@
+/**
+ Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
+
+ The examples provided by Facebook are for non-commercial testing and evaluation
+ purposes only. Facebook reserves all rights not expressly granted.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+import XCTest
+
+final class LoadMoreViewControllerUITests: UITestCase {
+
+ func test_whenScrollingToTheBottom_thatNewItemsAreLoaded() {
+ let collectionViews = app.collectionViews
+ collectionViews.cells.staticTexts["Tail Loading"].tap()
+
+ // Swipe up until the last element before loading new data is visible
+ let lastElem = collectionViews.cells.staticTexts["20"]
+ while !lastElem.exists || !app.windows.element(boundBy: 0).frame.contains(lastElem.frame) {
+ collectionViews.element.swipeUp()
+ }
+
+ // Wait for item "21" to be loaded asynchronously
+ let newlyLoadedElement = collectionViews.cells.staticTexts["21"]
+ waitToAppear(element: newlyLoadedElement)
+ }
+
+}
diff --git a/Examples/Examples-iOS/IGListKitExamples-UITests/MixedDataViewControllerUITests.swift b/Examples/Examples-iOS/IGListKitExamples-UITests/MixedDataViewControllerUITests.swift
new file mode 100644
index 0000000..50d91d5
--- /dev/null
+++ b/Examples/Examples-iOS/IGListKitExamples-UITests/MixedDataViewControllerUITests.swift
@@ -0,0 +1,107 @@
+/**
+ Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
+
+ The examples provided by Facebook are for non-commercial testing and evaluation
+ purposes only. Facebook reserves all rights not expressly granted.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+import XCTest
+
+final class MixedDataViewControllerUITests: UITestCase {
+
+ override func setUp() {
+ super.setUp()
+
+ enterMixedDataDetailScreen()
+ }
+
+ func test_whenSelectingAll_thatAllSectionTypesArePresent() {
+ mixedDataNavigationBarElement().buttons["All"].tap()
+
+ XCTAssertTrue(expandableSectionElement().exists)
+ XCTAssertTrue(userSectionElement().exists)
+ XCTAssertTrue(gridSectionElement().exists)
+ }
+
+ func test_whenSelectingColors_thatOnlyGridSectionsArePresent() {
+ mixedDataNavigationBarElement().buttons["Colors"].tap()
+
+ XCTAssertFalse(expandableSectionElement().exists)
+ XCTAssertFalse(userSectionElement().exists)
+ XCTAssertTrue(gridSectionElement().exists)
+ }
+
+ func test_whenSelectingText_thatOnlyExpandableSectionsArePresent() {
+ mixedDataNavigationBarElement().buttons["Text"].tap()
+
+ XCTAssertTrue(expandableSectionElement().exists)
+ XCTAssertFalse(userSectionElement().exists)
+ XCTAssertFalse(gridSectionElement().exists)
+ }
+
+ func test_whenSelectingUsers_thatOnlyUserSectionsArePresent() {
+ mixedDataNavigationBarElement().buttons["Users"].tap()
+
+ XCTAssertFalse(expandableSectionElement().exists)
+ XCTAssertTrue(userSectionElement().exists)
+ XCTAssertFalse(gridSectionElement().exists)
+ }
+
+ func test_whenExpandingExpandableSection_thatHeightIsIncreased() {
+ mixedDataNavigationBarElement().buttons["Text"].tap()
+
+ let expandableSection = expandableSectionElement()
+ let collapsedFrame = expandableSection.frame
+
+ // Expand
+ expandableSection.tap()
+ let expandedFrame = expandableSection.frame
+
+ XCTAssertTrue(expandedFrame.size.height > collapsedFrame.size.height)
+ }
+
+ func test_whenCollapsingExpandableSection_thatHeightIsDecreased() {
+ mixedDataNavigationBarElement().buttons["Text"].tap()
+
+ let expandableSection = expandableSectionElement()
+
+ // Expand
+ expandableSection.tap()
+ let expandedFrame = expandableSection.frame
+
+ // Collapse
+ expandableSection.tap()
+ let collapsedFrame = expandableSection.frame
+
+ XCTAssertTrue(collapsedFrame.size.height < expandedFrame.size.height)
+ }
+
+
+ private func expandableSectionElement() -> XCUIElement {
+ return app.collectionViews.cells.staticTexts["Maecenas faucibus mollis interdum. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit."]
+ }
+
+ private func userSectionElement() -> XCUIElement {
+ return app.collectionViews.cells.staticTexts["@ryanolsonk"]
+ }
+
+ private func gridSectionElement() -> XCUIElement {
+ return app.collectionViews.cells.staticTexts["1"]
+ }
+
+ private func mixedDataNavigationBarElement() -> XCUIElement {
+ return app.navigationBars["Mixed Data"]
+ }
+
+ private func enterMixedDataDetailScreen() {
+ app.collectionViews.cells.staticTexts["Mixed Data"].tap()
+ }
+
+}
diff --git a/Examples/Examples-iOS/IGListKitExamples-UITests/SearchViewControllerUITests.swift b/Examples/Examples-iOS/IGListKitExamples-UITests/SearchViewControllerUITests.swift
new file mode 100644
index 0000000..65a5c3d
--- /dev/null
+++ b/Examples/Examples-iOS/IGListKitExamples-UITests/SearchViewControllerUITests.swift
@@ -0,0 +1,57 @@
+/**
+ Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
+
+ The examples provided by Facebook are for non-commercial testing and evaluation
+ purposes only. Facebook reserves all rights not expressly granted.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+import XCTest
+
+final class SearchViewControllerUITests: UITestCase {
+
+ var collectionViews: XCUIElementQuery!
+
+ override func setUp() {
+ super.setUp()
+
+ collectionViews = app.collectionViews
+ collectionViews.cells.staticTexts["Search Autocomplete"].tap()
+ }
+
+ func test_whenLoading_thatSomeResultsAreShown() {
+ let tacos = collectionViews.cells.staticTexts["tacos"]
+ let small = collectionViews.cells.staticTexts["small"]
+ XCTAssertTrue(tacos.exists)
+ XCTAssertTrue(small.exists)
+ }
+
+ func test_whenSearchingForText_thatResultsGetFiltered() {
+ let searchField = collectionViews.searchFields.element
+ searchField.tap()
+ searchField.typeText("tac")
+
+ let tacos = collectionViews.cells.staticTexts["tacos"]
+ let small = collectionViews.cells.staticTexts["small"]
+ XCTAssertTrue(tacos.exists)
+ XCTAssertFalse(small.exists)
+ }
+
+ func test_whenClearingText_thatResultsFilterIsRemoved() {
+ let searchField = collectionViews.searchFields.element
+ searchField.tap()
+ searchField.typeText("tac")
+ searchField.buttons.element.tap()
+
+ let tacos = collectionViews.cells.staticTexts["tacos"]
+ let small = collectionViews.cells.staticTexts["small"]
+ XCTAssertTrue(tacos.exists)
+ XCTAssertTrue(small.exists)
+ }
+}
diff --git a/Examples/Examples-iOS/IGListKitExamples-UITests/UITestCase.swift b/Examples/Examples-iOS/IGListKitExamples-UITests/UITestCase.swift
new file mode 100644
index 0000000..2c10b4e
--- /dev/null
+++ b/Examples/Examples-iOS/IGListKitExamples-UITests/UITestCase.swift
@@ -0,0 +1,85 @@
+/**
+ Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
+
+ The examples provided by Facebook are for non-commercial testing and evaluation
+ purposes only. Facebook reserves all rights not expressly granted.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+import XCTest
+
+class UITestCase: XCTestCase {
+
+ let app = XCUIApplication()
+
+ override func setUp() {
+ super.setUp()
+
+ continueAfterFailure = false
+ app.launch()
+ }
+
+ override func tearDown() {
+ super.tearDown()
+
+ app.terminate()
+ }
+
+
+ // Adapted from http://masilotti.com/xctest-helpers/
+ internal func waitToAppear(element: XCUIElement,
+ timeout: TimeInterval = 2,
+ file: String = #file,
+ line: UInt = #line) {
+ waitToAppear(elements: [element], timeout: timeout, file: file, line: line)
+ }
+
+ internal func waitToAppear(elements: [XCUIElement],
+ timeout: TimeInterval = 2,
+ file: String = #file,
+ line: UInt = #line) {
+ waitTo(appear: true, elements: elements, timeout: timeout, file: file, line: line)
+ }
+
+ internal func waitToDisappear(element: XCUIElement,
+ timeout: TimeInterval = 2,
+ file: String = #file,
+ line: UInt = #line) {
+ waitToDisappear(elements: [element], timeout: timeout, file: file, line: line)
+ }
+
+ internal func waitToDisappear(elements: [XCUIElement],
+ timeout: TimeInterval = 2,
+ file: String = #file,
+ line: UInt = #line) {
+ waitTo(appear: false, elements: elements, timeout: timeout, file: file, line: line)
+ }
+
+ internal func waitTo(appear: Bool,
+ elements: [XCUIElement],
+ timeout: TimeInterval = 2,
+ file: String = #file,
+ line: UInt = #line) {
+ let existsPredicate = NSPredicate(format: "exists == \(appear)")
+ elements.forEach { element in
+ expectation(for: existsPredicate, evaluatedWith: element, handler: nil)
+ }
+
+ waitForExpectations(timeout: timeout) { error in
+ if error != nil {
+ let message = "Failed to \(appear ? "" : "not ")find element(s) after \(timeout) seconds."
+ self.recordFailure(withDescription: message,
+ inFile: file,
+ atLine: line,
+ expected: true)
+ }
+ }
+ }
+
+}
diff --git a/Examples/Examples-iOS/IGListKitExamples.xcodeproj/project.pbxproj b/Examples/Examples-iOS/IGListKitExamples.xcodeproj/project.pbxproj
index 2e98ef7..0955689 100644
--- a/Examples/Examples-iOS/IGListKitExamples.xcodeproj/project.pbxproj
+++ b/Examples/Examples-iOS/IGListKitExamples.xcodeproj/project.pbxproj
@@ -61,6 +61,11 @@
821BC4B81DB8B48300172ED0 /* StoryboardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821BC4B71DB8B48300172ED0 /* StoryboardCell.swift */; };
821BC4BA1DB8B61200172ED0 /* StoryboardLabelSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821BC4B91DB8B61200172ED0 /* StoryboardLabelSectionController.swift */; };
82D91B691DBA0EF300E62758 /* SingleSectionStoryboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82D91B681DBA0EF300E62758 /* SingleSectionStoryboardViewController.swift */; };
+ 9518E3C31DED03520008CC46 /* UITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9518E3C21DED03510008CC46 /* UITestCase.swift */; };
+ 9518E3C51DED057E0008CC46 /* LoadMoreViewControllerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9518E3C41DED057E0008CC46 /* LoadMoreViewControllerUITests.swift */; };
+ 9518E3C71DED18370008CC46 /* SearchViewControllerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9518E3C61DED18370008CC46 /* SearchViewControllerUITests.swift */; };
+ 9518E3C91DED1BCB0008CC46 /* MixedDataViewControllerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9518E3C81DED1BCB0008CC46 /* MixedDataViewControllerUITests.swift */; };
+ 9518E3CB1DED27840008CC46 /* DemosViewControllerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9518E3CA1DED27840008CC46 /* DemosViewControllerUITests.swift */; };
986FB7131DBBA60900A65C18 /* Messages.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 986FB7121DBBA60900A65C18 /* Messages.framework */; };
986FB7161DBBA60900A65C18 /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 986FB7151DBBA60900A65C18 /* MessagesViewController.swift */; };
986FB71B1DBBA60900A65C18 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 986FB71A1DBBA60900A65C18 /* Assets.xcassets */; };
@@ -76,6 +81,13 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
+ 95F7F9161DE5006C00A64FEE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 2961B3821D68B031001C9451 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2961B3891D68B031001C9451;
+ remoteInfo = IGListKitExamples;
+ };
986FB71D1DBBA60900A65C18 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 2961B3821D68B031001C9451 /* Project object */;
@@ -167,6 +179,13 @@
821BC4B71DB8B48300172ED0 /* StoryboardCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardCell.swift; sourceTree = ""; };
821BC4B91DB8B61200172ED0 /* StoryboardLabelSectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardLabelSectionController.swift; sourceTree = ""; };
82D91B681DBA0EF300E62758 /* SingleSectionStoryboardViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleSectionStoryboardViewController.swift; sourceTree = ""; };
+ 9518E3C21DED03510008CC46 /* UITestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITestCase.swift; sourceTree = ""; };
+ 9518E3C41DED057E0008CC46 /* LoadMoreViewControllerUITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadMoreViewControllerUITests.swift; sourceTree = ""; };
+ 9518E3C61DED18370008CC46 /* SearchViewControllerUITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchViewControllerUITests.swift; sourceTree = ""; };
+ 9518E3C81DED1BCB0008CC46 /* MixedDataViewControllerUITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MixedDataViewControllerUITests.swift; sourceTree = ""; };
+ 9518E3CA1DED27840008CC46 /* DemosViewControllerUITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemosViewControllerUITests.swift; sourceTree = ""; };
+ 95F7F9111DE5006B00A64FEE /* IGListKitExamples-UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "IGListKitExamples-UITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 95F7F9151DE5006C00A64FEE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
97C361B62DE81B6EF3C43D32 /* Pods-MessageExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MessageExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MessageExtension/Pods-MessageExtension.debug.xcconfig"; sourceTree = ""; };
986FB7111DBBA60900A65C18 /* IGListKitMessageExample.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IGListKitMessageExample.appex; sourceTree = BUILT_PRODUCTS_DIR; };
986FB7121DBBA60900A65C18 /* Messages.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Messages.framework; path = System/Library/Frameworks/Messages.framework; sourceTree = SDKROOT; };
@@ -193,6 +212,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 95F7F90E1DE5006B00A64FEE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
986FB70E1DBBA60900A65C18 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -253,6 +279,7 @@
2961B38C1D68B031001C9451 /* IGListKitExamples */,
986FB7141DBBA60900A65C18 /* IGListKitMessageExample */,
986FB7321DBBAD8600A65C18 /* IGListKitTodayExample */,
+ 95F7F9121DE5006C00A64FEE /* IGListKitExamples-UITests */,
2961B38B1D68B031001C9451 /* Products */,
586CEEF7A60B53C23ED20E47 /* Pods */,
0853E82EF5C5E4BD4E0760E3 /* Frameworks */,
@@ -265,6 +292,7 @@
2961B38A1D68B031001C9451 /* IGListKitExamples.app */,
986FB7111DBBA60900A65C18 /* IGListKitMessageExample.appex */,
986FB72F1DBBAD8600A65C18 /* IGListKitTodayExample.appex */,
+ 95F7F9111DE5006B00A64FEE /* IGListKitExamples-UITests.xctest */,
);
name = Products;
sourceTree = "";
@@ -364,6 +392,19 @@
path = ..;
sourceTree = "";
};
+ 95F7F9121DE5006C00A64FEE /* IGListKitExamples-UITests */ = {
+ isa = PBXGroup;
+ children = (
+ 95F7F9151DE5006C00A64FEE /* Info.plist */,
+ 9518E3C21DED03510008CC46 /* UITestCase.swift */,
+ 9518E3C41DED057E0008CC46 /* LoadMoreViewControllerUITests.swift */,
+ 9518E3C61DED18370008CC46 /* SearchViewControllerUITests.swift */,
+ 9518E3C81DED1BCB0008CC46 /* MixedDataViewControllerUITests.swift */,
+ 9518E3CA1DED27840008CC46 /* DemosViewControllerUITests.swift */,
+ );
+ path = "IGListKitExamples-UITests";
+ sourceTree = "";
+ };
986FB7141DBBA60900A65C18 /* IGListKitMessageExample */ = {
isa = PBXGroup;
children = (
@@ -425,6 +466,24 @@
productReference = 2961B38A1D68B031001C9451 /* IGListKitExamples.app */;
productType = "com.apple.product-type.application";
};
+ 95F7F9101DE5006B00A64FEE /* IGListKitExamples-UITests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 95F7F91A1DE5006C00A64FEE /* Build configuration list for PBXNativeTarget "IGListKitExamples-UITests" */;
+ buildPhases = (
+ 95F7F90D1DE5006B00A64FEE /* Sources */,
+ 95F7F90E1DE5006B00A64FEE /* Frameworks */,
+ 95F7F90F1DE5006B00A64FEE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 95F7F9171DE5006C00A64FEE /* PBXTargetDependency */,
+ );
+ name = "IGListKitExamples-UITests";
+ productName = "IGListKitExamples-UITests";
+ productReference = 95F7F9111DE5006B00A64FEE /* IGListKitExamples-UITests.xctest */;
+ productType = "com.apple.product-type.bundle.ui-testing";
+ };
986FB7101DBBA60900A65C18 /* IGListKitMessageExample */ = {
isa = PBXNativeTarget;
buildConfigurationList = 986FB7221DBBA60900A65C18 /* Build configuration list for PBXNativeTarget "IGListKitMessageExample" */;
@@ -478,6 +537,11 @@
LastSwiftMigration = 0800;
ProvisioningStyle = Automatic;
};
+ 95F7F9101DE5006B00A64FEE = {
+ CreatedOnToolsVersion = 8.1;
+ ProvisioningStyle = Automatic;
+ TestTargetID = 2961B3891D68B031001C9451;
+ };
986FB7101DBBA60900A65C18 = {
CreatedOnToolsVersion = 8.1;
ProvisioningStyle = Automatic;
@@ -504,6 +568,7 @@
2961B3891D68B031001C9451 /* IGListKitExamples */,
986FB7101DBBA60900A65C18 /* IGListKitMessageExample */,
986FB72E1DBBAD8600A65C18 /* IGListKitTodayExample */,
+ 95F7F9101DE5006B00A64FEE /* IGListKitExamples-UITests */,
);
};
/* End PBXProject section */
@@ -522,6 +587,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 95F7F90F1DE5006B00A64FEE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
986FB70F1DBBA60900A65C18 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -699,6 +771,18 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 95F7F90D1DE5006B00A64FEE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 9518E3C51DED057E0008CC46 /* LoadMoreViewControllerUITests.swift in Sources */,
+ 9518E3CB1DED27840008CC46 /* DemosViewControllerUITests.swift in Sources */,
+ 9518E3C91DED1BCB0008CC46 /* MixedDataViewControllerUITests.swift in Sources */,
+ 9518E3C71DED18370008CC46 /* SearchViewControllerUITests.swift in Sources */,
+ 9518E3C31DED03520008CC46 /* UITestCase.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
986FB70D1DBBA60900A65C18 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -722,6 +806,11 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
+ 95F7F9171DE5006C00A64FEE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2961B3891D68B031001C9451 /* IGListKitExamples */;
+ targetProxy = 95F7F9161DE5006C00A64FEE /* PBXContainerItemProxy */;
+ };
986FB71E1DBBA60900A65C18 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 986FB7101DBBA60900A65C18 /* IGListKitMessageExample */;
@@ -873,6 +962,37 @@
};
name = Release;
};
+ 95F7F9181DE5006C00A64FEE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
+ INFOPLIST_FILE = "IGListKitExamples-UITests/Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 10.1;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.instagram.IGListKitExamples-UITests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_VERSION = 3.0;
+ TEST_TARGET_NAME = IGListKitExamples;
+ };
+ name = Debug;
+ };
+ 95F7F9191DE5006C00A64FEE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
+ INFOPLIST_FILE = "IGListKitExamples-UITests/Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 10.1;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.instagram.IGListKitExamples-UITests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 3.0;
+ TEST_TARGET_NAME = IGListKitExamples;
+ };
+ name = Release;
+ };
986FB7201DBBA60900A65C18 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D7C1118BDF9C30E23DC1953E /* Pods-IGListKitMessageExample.debug.xcconfig */;
@@ -970,6 +1090,14 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ 95F7F91A1DE5006C00A64FEE /* Build configuration list for PBXNativeTarget "IGListKitExamples-UITests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 95F7F9181DE5006C00A64FEE /* Debug */,
+ 95F7F9191DE5006C00A64FEE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ };
986FB7221DBBA60900A65C18 /* Build configuration list for PBXNativeTarget "IGListKitMessageExample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme b/Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme
index 7ce872a..33e2de9 100644
--- a/Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme
+++ b/Examples/Examples-iOS/IGListKitExamples.xcodeproj/xcshareddata/xcschemes/IGListKitExamples.xcscheme
@@ -26,8 +26,19 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ codeCoverageEnabled = "YES">
+
+
+
+
+
+
+
+
+
+
+
+