Skip to content

[webview_flutter] Convert from XCTest to Swift Testing#12243

Merged
auto-submit[bot] merged 4 commits into
flutter:mainfrom
stuartmorgan-g:webvwiew-swift-testing
Jul 20, 2026
Merged

[webview_flutter] Convert from XCTest to Swift Testing#12243
auto-submit[bot] merged 4 commits into
flutter:mainfrom
stuartmorgan-g:webvwiew-swift-testing

Conversation

@stuartmorgan-g

Copy link
Copy Markdown
Collaborator

Converts all of the webview_flutter unit tests from XCTest to Swift testing. This was mostly done by Gemini (mostly purely mechanical conversion), with some minor cleanup after I reviewed it. As with other conversions, this is focused on converting more or less directly, without adopting new features like parameterization.

Part of flutter/flutter#180787

Pre-Review Checklist

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

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request migrates the unit tests for the WKWebView implementation from the XCTest framework to the Swift Testing framework. The changes include replacing XCTest assertions with #expect, converting test classes to @Suite structs, and updating asynchronous test patterns to use modern Swift concurrency. The review feedback suggests using the Skip error to dynamically skip tests instead of returning early, and using #expect(throws: Never.self) to assert that no error is thrown instead of using withKnownIssue.

@LongCatIsLooong LongCatIsLooong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It looks like gemini is making some strange choices around async and throw tests. Most comments aren't blocking except the timeout one.

registrar.logFlutterMethodFailure(
PigeonError(code: "code", message: "message", details: nil), methodName: "aMethod"))
// Method should log a message and not throw an error.
#expect(throws: Never.self) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Uhm I have not used swift testing that much, but this doesn't look right. How can you throw a Never if you can't construct one in the first place? So from reading this the expectation seems to be "the closure never throws"?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh I see gemini code review suggested that and the expectation is indeed "the closure does not throw". Never mind then. Although the testing framework treats all uncaught exceptions as failures so the Never.self is probably not really needed.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I dug into this test more, and the structure is even weirder than it seemed at first glance because the method being called isn't throws. So once the throws: Never.self wrapper is removed you get a warning about calling try on something that doesn't throw.

I settled for just calling the method directly in the test, and putting a comment on the test saying not to add throws to it, and why. It's a bit weird, but seemed like the simplest way of expressing what the test is trying to prevent regressing.

class ScriptMessageProxyAPITests: XCTestCase {
@MainActor func testName() {
@Suite struct ScriptMessageProxyAPITests {
@MainActor @Test func name() throws {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: this test doesn't actually throw does it? Since we are using try? ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same question for the test below.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I didn't notice how much the tests in this package used try?. I think in a Swift Testing world what we generally want is to try instead since the test system is designed to support reporting exceptions, so if something throws that was supposed to succeed it's better to get the exception than to just get a nil comparison failure in an #expect.

I scrubbed try? out of everything but the constructor tests. For those the explicit nil check seemed cleaner than a comment saying why there's no check, so I removed throws from just those.


wait(for: [removeDataOfTypesExpectation], timeout: 10.0)
XCTAssertNotNil(removeDataOfTypesResult)
let _ = try await withCheckedThrowingContinuation {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IIRC withCheckedThrowingContinuation or @Test never times out by itself unless explicitly given a timeout value. Here if continuation.resume is never called, I suspect the test will hang.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also this test reads a bit weird since gemini went out of its way to type the continuation CheckedContinuation<Bool, Error> but never actually uses the return value.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

IIRC withCheckedThrowingContinuation or @Test never times out by itself unless explicitly given a timeout value. Here if continuation.resume is never called, I suspect the test will hang.

Yeah. In theory that's a feature (see here and here), so it's how we've been doing Swift Testing conversions.

I will say I don't love the dev experience, so longer term we may want to have a Flutter-team-level discussion around this. It was already kind of annoying for manual development, but what I discovered while doing this round of conversions using Gemini instead of doing it manually is that it's quite bad for agentic development because the agent will frequently make a bunch of changes, kick of the tests to see how they turn out, and then just say "Now I'll wait for the tests to finish"... and just wait forever until a human intercedes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

(If we do later decided to move away from tests that can hang forever, I think we would sweep the entire repo and add timeLimit traits to everything at a suite level.)

@stuartmorgan-g stuartmorgan-g added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 20, 2026
@auto-submit
auto-submit Bot merged commit ee742d6 into flutter:main Jul 20, 2026
13 checks passed
pull Bot pushed a commit to Klomgor/flutter that referenced this pull request Jul 21, 2026
…er#189782)

flutter/packages@611899b...8260a1e

2026-07-20 jmccandless@google.com [cupertino_ui] Publish pre-release
0.0.2 (flutter/packages#12251)
2026-07-20 43054281+camsim99@users.noreply.github.com
[camera_android_camerax] Add `AGENTS.md` (flutter/packages#12066)
2026-07-20 jmccandless@google.com [cupertino_ui] Undo unpublished
version info (flutter/packages#12252)
2026-07-20 42726313+dao-wkm@users.noreply.github.com
[video_player_android] Avoid sending unset duration on initialization
(flutter/packages#11709)
2026-07-20 stuartmorgan@google.com [webview_flutter] Convert from XCTest
to Swift Testing (flutter/packages#12243)
2026-07-20 stuartmorgan@google.com [various] Convert example boilerplate
from Java to Kotlin (flutter/packages#12201)
2026-07-20 jmccandless@google.com [material_ui, cupertino_ui] Update
changelogs for the prerelease (flutter/packages#12249)
2026-07-20 engine-flutter-autoroll@skia.org Roll Flutter from
8005793 to cab057d (2 revisions) (flutter/packages#12248)
2026-07-20 shuminlian@gmail.com [in_app_purchase_android] Add obfuscated
profile ID purchase param (flutter/packages#12080)
2026-07-20 jmccandless@google.com [material_ui] Unpin
material_color_utilities (flutter/packages#12225)

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 CICD Run CI/CD p: webview_flutter platform-ios platform-macos

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants