mirror of
https://codeberg.org/secana/Forji.git
synced 2026-06-16 05:13:55 -07:00
Add open-to-clear UI regression test for notifications (#32)
Covers the in-app path: open an unread notification, then confirm it leaves the Unread filter after a refresh. Validated against the seeded Docker Forgejo via just mutating_a_classes=NotificationsUITests test-mutating-a; it fails on the pre-fix code and passes with the fix. The merged-instance and system-notification open paths apply the same fix but aren't reachable from this single-instance UI harness. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f42980c11c
commit
ce32f4cae5
1 changed files with 63 additions and 0 deletions
|
|
@ -49,4 +49,67 @@ final class NotificationsUITests: ForgejoUITestBase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue