mirror of
https://github.com/Instagram/IGListKit
synced 2026-05-24 09:48:21 +00:00
132 lines
4.3 KiB
Swift
132 lines
4.3 KiB
Swift
|
|
/*
|
||
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||
|
|
*
|
||
|
|
* This source code is licensed under the MIT license found in the
|
||
|
|
* LICENSE file in the root directory of this source tree.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import XCTest
|
||
|
|
|
||
|
|
final class FeedViewControllerUITests: UITestCase {
|
||
|
|
|
||
|
|
// MARK: - Short-cuts
|
||
|
|
|
||
|
|
private var app: XCUIApplication { XCUIApplication() }
|
||
|
|
|
||
|
|
/// The collection-view that shows the FeedViewController's feed.
|
||
|
|
private var feed: XCUIElement {
|
||
|
|
let collections = app.collectionViews
|
||
|
|
guard collections.count > 1 else { return collections.firstMatch }
|
||
|
|
|
||
|
|
for idx in 0..<collections.count {
|
||
|
|
let cv = collections.element(boundBy: idx)
|
||
|
|
if cv.buttons["optionsButton"].waitForExistence(timeout: 0.4) {
|
||
|
|
return cv
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return collections.element(boundBy: 1)
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Lifecycle
|
||
|
|
|
||
|
|
override func setUp() {
|
||
|
|
super.setUp()
|
||
|
|
enterFeedViewControllerDetailScreen()
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Tests
|
||
|
|
|
||
|
|
func test_whenLoadingInitialContent_postsAreDisplayed() {
|
||
|
|
waitToAppear(element: feed.cells.element(boundBy: 0), timeout: 5)
|
||
|
|
XCTAssertTrue(feed.cells.count > 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func test_whenRefreshing_newContentIsLoaded() {
|
||
|
|
waitToAppear(element: feed.cells.element(boundBy: 0), timeout: 5)
|
||
|
|
app.navigationBars["Feed View"].buttons["Refresh"].tap()
|
||
|
|
waitToAppear(element: feed, timeout: 5)
|
||
|
|
XCTAssertTrue(feed.exists)
|
||
|
|
}
|
||
|
|
|
||
|
|
func test_whenScrollingToBottom_loadMoreIndicatorAppears() {
|
||
|
|
waitToAppear(element: feed.cells.element(boundBy: 0), timeout: 5)
|
||
|
|
(0..<3).forEach { _ in feed.swipeUp() }
|
||
|
|
XCTAssertTrue(feed.cells.count > 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func test_whenTappingOptionsButton_actionSheetAppears() {
|
||
|
|
let firstPost = firstVisiblePost()
|
||
|
|
|
||
|
|
locateOptionsButton(in: firstPost).tap()
|
||
|
|
let sheet = app.sheets.firstMatch
|
||
|
|
waitToAppear(element: sheet, timeout: 2)
|
||
|
|
|
||
|
|
XCTAssertTrue(sheet.buttons["Delete"].exists)
|
||
|
|
XCTAssertTrue(sheet.buttons["Report"].exists)
|
||
|
|
|
||
|
|
app.tap()
|
||
|
|
}
|
||
|
|
|
||
|
|
func test_whenDeletingPost_postIsRemoved() {
|
||
|
|
let firstPost = firstVisiblePost()
|
||
|
|
let caption = firstPost.staticTexts.firstMatch.label
|
||
|
|
XCTAssertFalse(caption.isEmpty, "Post should contain a visible caption")
|
||
|
|
|
||
|
|
locateOptionsButton(in: firstPost).tap()
|
||
|
|
waitToAppear(element: app.sheets.firstMatch, timeout: 2)
|
||
|
|
app.sheets.firstMatch.buttons["Delete"].tap()
|
||
|
|
|
||
|
|
let deletedCell = feed.cells
|
||
|
|
.containing(.staticText, identifier: caption)
|
||
|
|
.firstMatch
|
||
|
|
|
||
|
|
XCTAssertTrue(
|
||
|
|
waitUntilGone(element: deletedCell, timeout: 5),
|
||
|
|
"Cell with caption “\(caption)” should disappear after deletion"
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Helpers
|
||
|
|
|
||
|
|
private func enterFeedViewControllerDetailScreen() {
|
||
|
|
let demo = app.collectionViews.staticTexts["Feed View"]
|
||
|
|
scrollToElement(demo, in: app.collectionViews)
|
||
|
|
XCTAssertTrue(demo.exists)
|
||
|
|
|
||
|
|
demo.tap()
|
||
|
|
XCTAssertTrue(app.navigationBars["Feed View"].exists)
|
||
|
|
}
|
||
|
|
|
||
|
|
@discardableResult
|
||
|
|
private func waitUntilGone(element: XCUIElement,
|
||
|
|
timeout: TimeInterval) -> Bool {
|
||
|
|
let gone = NSPredicate(format: "exists == false")
|
||
|
|
let exp = expectation(for: gone, evaluatedWith: element, handler: nil)
|
||
|
|
return XCTWaiter().wait(for: [exp], timeout: timeout) == .completed
|
||
|
|
}
|
||
|
|
|
||
|
|
private func firstVisiblePost() -> XCUIElement {
|
||
|
|
let post = feed.cells.element(boundBy: 0)
|
||
|
|
waitToAppear(element: post, timeout: 5)
|
||
|
|
return post
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Finds the trailing “…” button in a post, whatever Apple calls it this week.
|
||
|
|
private func locateOptionsButton(in post: XCUIElement) -> XCUIElement {
|
||
|
|
let predicate = NSPredicate(
|
||
|
|
format: "identifier == 'optionsButton' || " +
|
||
|
|
"label CONTAINS[c] 'ellipsis' || " +
|
||
|
|
"label CONTAINS[c] 'more'"
|
||
|
|
)
|
||
|
|
|
||
|
|
for container in [post, feed, app] {
|
||
|
|
let btn = container.descendants(matching: .any)
|
||
|
|
.matching(predicate)
|
||
|
|
.firstMatch
|
||
|
|
if btn.waitForExistence(timeout: 2) { return btn }
|
||
|
|
}
|
||
|
|
|
||
|
|
fatalError("Options button should appear somewhere on screen")
|
||
|
|
}
|
||
|
|
}
|