mirror of
https://codeberg.org/secana/Forji.git
synced 2026-06-16 05:13:55 -07:00
The trailing Dismiss swipe called the same setNotificationRead path as the leading Mark Read action, since ForgejoKit's NotificationService only exposes markAsRead (PATCH to-status=read). Dismiss therefore did nothing distinct and left the row visible under the All/Read filters, just relabeled. Drop the redundant action in both NotificationsOverviewView and MergedNotificationsOverviewView. The leading Mark Read swipe (shown for unread threads, full-swipe by default) remains the single, honest action. Reviewed-on: https://codeberg.org/secana/Forji/pulls/64
105 lines
4.6 KiB
Swift
105 lines
4.6 KiB
Swift
import XCTest
|
|
|
|
final class NotificationsUITests: ForgejoUITestBase {
|
|
|
|
// MARK: - Notifications (unread, filter, swipe mark-read)
|
|
|
|
@MainActor
|
|
func testNotifications() throws {
|
|
loginAndWaitForHome()
|
|
app.tabBars.buttons["Notifications"].tap()
|
|
|
|
let notificationsList = app.collectionViews.firstMatch
|
|
XCTAssertTrue(notificationsList.waitForExistence(timeout: 10))
|
|
XCTAssertTrue(app.staticTexts["testadmin/test-repo"].waitForExistence(timeout: 5))
|
|
|
|
// Filter by Read
|
|
let readButton = app.buttons["Read"]
|
|
XCTAssertTrue(readButton.waitForExistence(timeout: 5))
|
|
readButton.tap()
|
|
|
|
// Switch to All
|
|
let allButton = app.buttons["All"]
|
|
XCTAssertTrue(allButton.waitForExistence(timeout: 5))
|
|
allButton.tap()
|
|
|
|
// Switch back to Unread for swipe tests
|
|
let unreadButton = app.buttons["Unread"]
|
|
XCTAssertTrue(unreadButton.waitForExistence(timeout: 5))
|
|
unreadButton.tap()
|
|
XCTAssertTrue(notificationsList.waitForExistence(timeout: 10))
|
|
|
|
// Swipe right to mark as read
|
|
let firstCell = notificationsList.cells.firstMatch
|
|
XCTAssertTrue(firstCell.waitForExistence(timeout: 5))
|
|
firstCell.swipeRight()
|
|
|
|
let markReadButton = app.buttons["Mark Read"]
|
|
if markReadButton.waitForExistence(timeout: 3) {
|
|
markReadButton.tap()
|
|
}
|
|
}
|
|
|
|
// MARK: - Open-to-clear (#32)
|
|
|
|
/// Opening an unread notification marks it read on the server, so it leaves
|
|
/// the Unread filter on the next refresh.
|
|
///
|
|
/// Covers the in-app NotificationsOverviewView path: the tap gesture on the
|
|
/// row calls markReadOnOpen, which marks the thread read with
|
|
/// removeFromUnread: false so the row stays put during navigation and only
|
|
/// drops out of Unread on the next server fetch. The multi-instance and
|
|
/// system-notification open paths apply the same fix but aren't reachable
|
|
/// from this single-instance harness.
|
|
///
|
|
/// Sorts after testNotifications and opens whichever unread row is first
|
|
/// rather than a fixed one, so it's unaffected by the two notifications that
|
|
/// test consumes (the seed leaves several more).
|
|
@MainActor
|
|
func testOpeningNotificationMarksItRead() throws {
|
|
loginAndWaitForHome()
|
|
app.tabBars.buttons["Notifications"].tap()
|
|
|
|
let notificationsList = app.collectionViews.firstMatch
|
|
XCTAssertTrue(notificationsList.waitForExistence(timeout: 10))
|
|
|
|
// Make sure the Unread filter is active.
|
|
let unreadButton = app.buttons["Unread"]
|
|
XCTAssertTrue(unreadButton.waitForExistence(timeout: 5))
|
|
unreadButton.tap()
|
|
XCTAssertTrue(notificationsList.waitForExistence(timeout: 10))
|
|
|
|
// Remember the first unread notification's title (the row's first text)
|
|
// so we can assert that specific one leaves the Unread list.
|
|
let firstCell = notificationsList.cells.firstMatch
|
|
XCTAssertTrue(firstCell.waitForExistence(timeout: 10), "Expected at least one unread notification")
|
|
let openedTitle = firstCell.staticTexts.firstMatch.label
|
|
XCTAssertFalse(openedTitle.isEmpty, "Could not read the unread notification's title")
|
|
|
|
// Open it. Navigating into the detail proves the row was tappable; the
|
|
// nav bar title changes away from "Notifications" once it's on screen.
|
|
firstCell.tap()
|
|
let detailNavBar = app.navigationBars.element(boundBy: 0)
|
|
XCTAssertTrue(detailNavBar.waitForExistence(timeout: 10), "Detail view did not open")
|
|
XCTAssertNotEqual(detailNavBar.identifier, "Notifications", "Did not navigate into the notification detail")
|
|
|
|
// Back to the list.
|
|
app.navigationBars.buttons.element(boundBy: 0).tap()
|
|
XCTAssertTrue(notificationsList.waitForExistence(timeout: 10))
|
|
|
|
// Force a server refresh of Unread by toggling the filter. Opening marks
|
|
// the thread read but keeps the row visible until the next fetch, so this
|
|
// round-trip is what surfaces the open-to-clear behaviour.
|
|
app.buttons["Read"].tap()
|
|
XCTAssertTrue(notificationsList.waitForExistence(timeout: 10))
|
|
unreadButton.tap()
|
|
XCTAssertTrue(notificationsList.waitForExistence(timeout: 10))
|
|
|
|
// The opened notification should no longer be under Unread.
|
|
let openedRow = notificationsList.staticTexts[openedTitle]
|
|
XCTAssertFalse(
|
|
openedRow.waitForExistence(timeout: 5),
|
|
"Opened notification \"\(openedTitle)\" should have left the Unread filter after refresh",
|
|
)
|
|
}
|
|
}
|