| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- import XCTest
- /// Playback and queue UI tests — verifies play, queue add, play next, and clear operations.
- /// Uses `-MockNetwork` to ensure tests work without a live server.
- final class PlaybackUITests: XCTestCase {
- var app: XCUIApplication!
- override func setUpWithError() throws {
- continueAfterFailure = false
- app = XCUIApplication()
- app.launchArguments += ["-UITesting", "-MockNetwork"]
- }
- override func tearDownWithError() throws {
- app = nil
- }
- // MARK: - Helpers
- private func openCloudBrowser() {
- let cloudButton = app.buttons["cloudBrowserButton"]
- XCTAssertTrue(cloudButton.waitForExistence(timeout: 5), "Cloud browser button should exist")
- cloudButton.tap()
- }
- /// Navigates to a mock album's track list.
- /// Returns true if tracks are visible.
- @discardableResult
- private func navigateToAlbumTracks() -> Bool {
- openCloudBrowser()
- let albumsLink = app.buttons["cloud.browse.album"]
- guard albumsLink.waitForExistence(timeout: 5) else { return false }
- albumsLink.tap()
- // Wait for mock album row to appear
- let firstAlbumRow = app.buttons["cloud.album.row.album-1"]
- guard firstAlbumRow.waitForExistence(timeout: 5) else { return false }
- firstAlbumRow.tap()
- // Wait for track content to load
- let trackTitle = app.staticTexts["First Track"]
- return trackTitle.waitForExistence(timeout: 5)
- }
- // MARK: - Phase 2: Playback Tests
- /// Play a cloud track → mini player should appear with the track title.
- func testPlayCloudTrack() {
- app.launch()
- guard navigateToAlbumTracks() else {
- XCTFail("Could not navigate to album tracks")
- return
- }
- // Tap the first track row (the "Play All" button or a track)
- let playAllButton = app.buttons["Play All"]
- if playAllButton.waitForExistence(timeout: 3) {
- playAllButton.tap()
- } else {
- // Tap first track cell
- let firstTrack = app.cells.element(boundBy: 2) // skip header + play all section
- if firstTrack.waitForExistence(timeout: 3) {
- firstTrack.tap()
- }
- }
- // Dismiss the cloud browser
- let doneButton = app.buttons["Done"]
- if doneButton.waitForExistence(timeout: 3) {
- doneButton.tap()
- }
- // Mini player should appear
- let miniPlayer = app.otherElements["miniPlayer"]
- XCTAssertTrue(miniPlayer.waitForExistence(timeout: 10), "Mini player should appear after playing a track")
- // Track title should be visible in mini player
- let trackTitle = app.staticTexts.matching(identifier: "miniPlayer.trackTitle").firstMatch
- XCTAssertTrue(trackTitle.exists, "Mini player should show the track title")
- }
- /// Long-press a track → "Add to Queue" → queue view shows the entry.
- func testAddToQueue() {
- app.launch()
- guard navigateToAlbumTracks() else {
- XCTFail("Could not navigate to album tracks")
- return
- }
- // Long-press on a track to open context menu
- let trackCell = app.cells.element(boundBy: 3) // skip header + play all rows
- guard trackCell.waitForExistence(timeout: 3) else {
- XCTFail("Track cell should exist")
- return
- }
- trackCell.press(forDuration: 1.2)
- // Tap "Add to Queue" from context menu
- let addToQueueButton = app.buttons["Add to Queue"]
- guard addToQueueButton.waitForExistence(timeout: 3) else {
- // Context menu might not appear in simulator, skip gracefully
- return
- }
- addToQueueButton.tap()
- // Dismiss cloud browser
- let doneButton = app.buttons["Done"]
- if doneButton.waitForExistence(timeout: 3) {
- doneButton.tap()
- }
- // Open queue view (via mini player queue button or Now Playing)
- // First play something so queue is accessible
- // Queue is a sheet — check if we can open it from the mini player
- let miniPlayerQueue = app.buttons["miniPlayerQueue"]
- if miniPlayerQueue.waitForExistence(timeout: 5) {
- miniPlayerQueue.tap()
- // Queue should show the added entry
- let queueEmpty = app.otherElements["queue.emptyState"]
- XCTAssertFalse(queueEmpty.exists, "Queue should not be empty after adding a track")
- }
- }
- /// Long-press → "Play Next" → track appears at top of queue.
- func testQueuePlayNext() {
- app.launch()
- guard navigateToAlbumTracks() else {
- XCTFail("Could not navigate to album tracks")
- return
- }
- // Play first track to establish a now-playing state
- let playAllButton = app.buttons["Play All"]
- if playAllButton.waitForExistence(timeout: 3) {
- playAllButton.tap()
- }
- // Wait for playback to start
- sleep(2)
- // Navigate back to tracks if needed
- let backButton = app.navigationBars.buttons.firstMatch
- if backButton.exists {
- // We may still be on the album detail — long-press a different track
- }
- // Long-press second track
- let trackCell = app.cells.element(boundBy: 4)
- guard trackCell.waitForExistence(timeout: 3) else { return }
- trackCell.press(forDuration: 1.2)
- let playNextButton = app.buttons["Play Next"]
- guard playNextButton.waitForExistence(timeout: 3) else { return }
- playNextButton.tap()
- // Dismiss cloud browser
- let doneButton = app.buttons["Done"]
- if doneButton.waitForExistence(timeout: 3) {
- doneButton.tap()
- }
- // Open queue
- let miniPlayerQueue = app.buttons["miniPlayerQueue"]
- if miniPlayerQueue.waitForExistence(timeout: 5) {
- miniPlayerQueue.tap()
- // Queue should have entries
- let queueEmpty = app.otherElements["queue.emptyState"]
- XCTAssertFalse(queueEmpty.exists, "Queue should have the 'Play Next' entry")
- }
- }
- /// Add to queue → Clear → queue should be empty.
- func testQueueClear() {
- app.launch()
- guard navigateToAlbumTracks() else {
- XCTFail("Could not navigate to album tracks")
- return
- }
- // Play a track first
- let playAllButton = app.buttons["Play All"]
- if playAllButton.waitForExistence(timeout: 3) {
- playAllButton.tap()
- }
- sleep(2)
- // Add another track to queue via context menu
- let trackCell = app.cells.element(boundBy: 4)
- guard trackCell.waitForExistence(timeout: 3) else { return }
- trackCell.press(forDuration: 1.2)
- let addToQueueButton = app.buttons["Add to Queue"]
- guard addToQueueButton.waitForExistence(timeout: 3) else { return }
- addToQueueButton.tap()
- // Dismiss cloud browser
- let doneButton = app.buttons["Done"]
- if doneButton.waitForExistence(timeout: 3) {
- doneButton.tap()
- }
- // Open queue
- let miniPlayerQueue = app.buttons["miniPlayerQueue"]
- guard miniPlayerQueue.waitForExistence(timeout: 5) else {
- XCTFail("Mini player queue button should exist")
- return
- }
- miniPlayerQueue.tap()
- // Tap Clear
- let clearButton = app.buttons["queue.clearButton"]
- if clearButton.waitForExistence(timeout: 3) {
- clearButton.tap()
- // Queue should be empty (only Now Playing remains)
- // The clear button itself should disappear after clearing
- XCTAssertFalse(clearButton.waitForExistence(timeout: 3), "Clear button should disappear after clearing queue")
- }
- }
- }
|