Skip to content

[video_player] Convert iOS unit tests to Swift#10989

Merged
auto-submit[bot] merged 16 commits intoflutter:mainfrom
stuartmorgan-g:video-player-swift-tests
Feb 11, 2026
Merged

[video_player] Convert iOS unit tests to Swift#10989
auto-submit[bot] merged 16 commits intoflutter:mainfrom
stuartmorgan-g:video-player-swift-tests

Conversation

@stuartmorgan-g
Copy link
Collaborator

Converts all of the native unit tests in video_player_avfoundation to Swift:

  • For the UI integration tests, it's just a direct Swift conversion.
  • For the unit tests, I first did a direct conversion to Swift, including ensuring that everything passed in that version, then converted from XCTest to Swift Testing.

To minimize churn, I deliberately didn't address other technical debt in the tests (e.g., testing of player instances by making an entire plugin instance just to make a player). Some changes were necessary though:

  • Added some missing NS_ASSUME_NONNULL_BEGIN annotations to headers, to avoid having to deal with optional values in the Swift version of tests that couldn't ever actually be null.
  • Changed a utility method to take the necessary parts of AVAssetTrack instead of AVAssetTrack. The tests for that worked by subclassing AVAssetTrack even though it has no public initializers, which was extremely sketchy. It worked okay in Obj-C because Obj-C will let you get away with almost anything, but it doesn't compile in Swift.
  • Some tests that used Expectations to watch for KVO on player items extracted from the player internals have instead been changed to watch for player-level observable events. This is because I was having a lot of trouble getting KVO of AVPlayerItem to actually work in Swift, and rather than try to fix that when it wasn't great test design anyway, I just changed to using something that wasn't an internal detail anyway.

Part of flutter/flutter#119105

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2 3

@stuartmorgan-g
Copy link
Collaborator Author

stuartmorgan-g commented Feb 9, 2026

It may be useful for review to look at the changes before ec4b403 first, to see the more direct conversion, and then review ec4b403 separately to see what I had to change for Swift Testing.

@stuartmorgan-g stuartmorgan-g added the triage-ios Should be looked at in iOS triage label Feb 10, 2026

let listener = StubEventListener()
await withCheckedContinuation { initialized in
listener.initializationContinuation = initialized
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and other places in this file: if videoPlayerDidInitialize is not called, the test suite would get stuck (rather than marking this test as failure and continuing).

SwiftTesting has a time limit trait: https://developer.apple.com/documentation/testing/trait/timelimit(_:), but it's iOS 16+ only.

Google search sends me to https://www.donnywals.com/implementing-task-timeout-with-swift-concurrency. I cleaned up the code and updated it for Swift 6:

enum TestError: Error {
  case timeout
}

func withTimeout(seconds: TimeInterval, operation: @escaping @Sendable () async throws -> Void) async throws {
  try await withThrowingTaskGroup(of: Void.self) { group in
    group.addTask { try await operation() }
    group.addTask {
      try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
      throw TestError.timeout
    }
    
    defer { group.cancelAll() }
    try await group.next()!
  }
}

Then in the test:

    try await withTimeout(seconds: 5) {
      await withCheckedContinuation { continuation in
        listener.onInitialized {
          continuation.resume()
        }
      }
    }

I verified it working by adding a sleep:

    try await withTimeout(seconds: 5) {
      try await Task.sleep(nanoseconds: 10 * 1_000_000_000)
      // ...
    }

Copy link
Collaborator Author

@stuartmorgan-g stuartmorgan-g Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flutter style guidance is not to use timeouts, because timeouts are a source of flake. IIRC we used them with XCTest expectations because there wasn't a version without a timeout.

If a test hangs, then it will eventually fail in CI, and locally it's pretty obviously not working. What's the argument for adding timeouts here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nvm, i thought we use timeouts when using expectation API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nvm, i thought we use timeouts when using expectation API.

Oh i misread - we do use timeout in objc.

IIRC we used them with XCTest expectations because there wasn't a version without a timeout.

Gotcha. Good to know. I thought it was an explicit decision to make test fail faster. If we have the guideline i'm onboard.

@stuartmorgan-g stuartmorgan-g added autosubmit Merge PR when tree becomes green via auto submit App and removed triage-ios Should be looked at in iOS triage labels Feb 11, 2026
@auto-submit auto-submit bot merged commit d2c8969 into flutter:main Feb 11, 2026
81 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 12, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 12, 2026
github-merge-queue bot pushed a commit to flutter/flutter that referenced this pull request Feb 12, 2026
flutter/packages@1e50195...af1d610

2026-02-12 brunocorona.alcantar@gmail.com [video_player_avfoundation]
Fix regression where http headers were ignored (flutter/packages#10991)
2026-02-12 47866232+chunhtai@users.noreply.github.com [ci] Adds more ci
checks for batch release file integrity (flutter/packages#10859)
2026-02-12 stuartmorgan@google.com [google_maps_flutter] Create SDK 9
and 10 packages for iOS (flutter/packages#10852)
2026-02-12 katelovett@google.com Update codeowners
(flutter/packages#11004)
2026-02-11 engine-flutter-autoroll@skia.org Roll Flutter (stable) from
67323de to 44a626f (1372 revisions) (flutter/packages#10999)
2026-02-11 stuartmorgan@google.com [video_player] Convert iOS unit tests
to Swift (flutter/packages#10989)
2026-02-11 47866232+chunhtai@users.noreply.github.com [ci] updates
`update-release-info` to support batch release (flutter/packages#10958)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App p: video_player platform-ios platform-macos

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants