Repository navigation
Add device tests for CommunityToolkit.Maui, Apply Fixes for Bugs Found - #3344
Draft
TheCodeTraveler wants to merge 106 commits into
Draft
TheCodeTraveler wants to merge 106 commits into
TheCodeTraveler wants to merge 106 commits into
Conversation
Closed
TheCodeTraveler
added a commit
that referenced
this pull request
Oct 11, 2026
…evice tests - CameraProvider (Windows): the camera refresh skips a camera that InitializeCameraForCameraView could not open, instead of reading the VideoDeviceController of a MediaCapture that never initialized (its getter throws, so one such camera made the whole refresh fail). New Windows device test: CameraProviderWindowsTests.RefreshWhileAnotherCaptureHoldsACameraListsExactlyTheCamerasThatCanBeOpened. (Copilot review on #3344) - Device tests: the AttachAndRun tests of the Maui, MediaElement and Camera apps wait for the Loaded and Unloaded events they count. OnLoadedAsync returns once the view is loaded, which can come before MAUI raises Loaded on a slow emulator (Android API 28 in CI). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
We're now up to 89.5% Line Coverage and 82% Branch coverage across all unit tests and device tests. That's pretty great! Code Coverage Report: |
ne0rrmatrix
added a commit
to ne0rrmatrix/EbpubReaderV2
that referenced
this pull request
Oct 14, 2026
- Unit tests for CalibreCoverUrl, OpdsEntryStagingCache, EpubPathUtilities, EpubArchive and PositionSyncService. - tests/DisplayBook.DeviceTests: a MAUI app that runs xUnit on the device (DeviceRunners), covering code that calls MAUI APIs: BookStorageService, BookDatabase, OpdsServerRepository, OpdsCatalogCache, FirebaseAuthService (SecureStorage), GoogleBooksOptions (Preferences) and the value converters. Modelled on CommunityToolkit/Maui#3344. - tools/coverage.ps1: unit tests + Windows device tests under dotnet-coverage, merged into artifacts/coverage/coverage.xml (Visual Studio XML). - .github/workflows/build.yml: build, tests and coverage between the SonarQube Cloud scanner's begin/end. - Android signing: the keystore and its passwords leave the repository. They now come from Secrets.local.props locally and from repository secrets in CI; without them Android builds sign with the debug key.
2 tasks done
…the bugs they found Platform code that the net10.0 unit tests cannot reach is now covered by device tests that run inside real apps on Android, iOS, Mac Catalyst and Windows. There is one device-test app per shipped feature package (CommunityToolkit.Maui.DeviceTests for CommunityToolkit.Maui, .Core and .Maps; CommunityToolkit.Maui.MediaElement.DeviceTests; CommunityToolkit.Maui.Camera.DeviceTests), built like dotnet/maui's device tests: xUnit, a vendored test runner and XHarness. eng/devices/android.ps1, ios.ps1, catalyst.ps1 and windows.ps1 build and run them locally and in CI; eng/devices/README.md and src/CommunityToolkit.Maui.DeviceTests/README.md describe how to run and write them. The Build workflow (dotnet-build.yml) calls the reusable Device Tests workflow (device-tests.yml), which runs every app on Android API 28 and 36, the iOS simulator, Mac Catalyst and Windows (packaged and unpackaged). Its Code Coverage job merges the unit-test and device-test coverage into one report. Tool versions shared by the workflows live in .github/workflows/shared.env. The tests found bugs in the libraries, which this change fixes: #3307, #2827, #1818, #1826, #2358, #1845, #3091, #2320, #2153, #1879, #2078, #2570, #3079, #3113, #2900, #3212, #2519, #3171, #3050, #2322 and #2208, and in part #3317, #2894, #3081, #2538, #2691, #3063, #2952, #1987, #2645, #3220, #3248, #3066 and #3247. Rebased onto main as one commit. Conflicts: - StatusBar.android.cs: keeps #3189's window flags (the decor never fits the system windows, API < 30 also clears LayoutNoLimits, nothing depends on transparency) with this change's FindChildWithTag lookups. This change's alpha-0 check is no longer needed. The Android StatusBar device tests now expect #3189's flags. - Popup.shared.cs, PopupPage.shared.cs: keeps #3345's DefaultPopupSettings.BackgroundColorDark and OnInitializing, and this change's Style support. A value or binding set on the Popup, like the AppThemeBinding that #3345 set in the constructor, takes precedence over every Style (7 of 8 PopupStyleTests fail with it), so Popup.BackgroundColor stays null by default and the popup's Border shows DefaultPopupSettings.BackgroundColor, or BackgroundColorDark in the dark theme, following theme changes. #3345's two default-color tests now expect Popup.BackgroundColor to be null and check the Border. Also: actions/upload-artifact and download-artifact pinned to main's 7.0.2 and 8.0.2 in the device-test and coverage jobs; the empty property pattern (is { }), which CONTRIBUTING.md now asks to avoid, replaced by type patterns; the comments of DialogFragmentService and its tests no longer say that StatusBar.SetColor treats colors without alpha as transparent; and the Sample's popups that set black text but no background color (UpdatingPopup, CollectionViewPopup, ComplexPopup, CsharpBindingPopup and the Popup Sizing Issues popup) now show white text in the dark theme, on #3345's black default background (DefaultPopupSettings.BackgroundColorDark). Co-authored-by: James Crutchley <ne0rmatrix@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TheCodeTraveler
force-pushed
the
Add-device-tests-and-ui-tests
branch
from
October 16, 2026 04:57
2cda4d3 to
3f57379
Compare
…and agents
CONTRIBUTING.md gains a Comments section: names say what the code does;
comments only explain why (a non-intuitive decision, a platform quirk or
workaround, an ordering constraint, code that looks out of scope).
.github/copilot-instructions.md and .github/instructions/codestyle.instructions.md
carry the same rule and the existing CONTRIBUTING.md rule against the empty
property pattern `is { }`, and the range-indexer example no longer teaches
comments that restate the code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On .NET 11, StatusBar.SetStyle and StatusBarBehavior.StatusBarStyle only set Window.StatusBarTheme, which UIKit ignores when Info.plist sets UIViewControllerBasedStatusBarAppearance to false: the setup that the toolkit documents for StatusBarBehavior. The style stopped changing, while the same app with the .NET 10 code (UIApplication.SetStatusBarStyle) shows it. .NET 11 rc.1 builds against the iOS 26.5 SDK, and UIKit applies UIApplication.SetStatusBarStyle with that key in every app built with an iOS SDK before 27.0, with or without the UIScene life cycle; only apps built with the iOS 27 SDK ignore it. With the key set to false, the .NET 11 code now also sets the style of the whole app with UIApplication.SetStatusBarStyle, as .NET 10 does, and writes its "remove the key" trace message only when UIKit ignores that call too. The remarks and comments no longer say that every .NET 11 app is scene-based or that scene-based apps ignore UIApplication.SetStatusBarStyle: the iOS SDK the app is built with decides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…orm to 100%" typo
The Button, Multiple Button, Toggle Size, Cannot Be Dismissed, Return Result and Opened Event Simple popups have a fixed light background (White, or LightCoral for the Button popup), but their description label used a "Content" style without a TextColor. Because the label has an explicit Style, the Sample's implicit Label style does not apply to it, so the label used the platform's default text colour, which is white in dark theme (the implicit style would have made it white too): the text vanished on iOS, Android and Windows. Each Content style now sets TextColor #000, like the Title style next to it.
The description read "will confirm to 100%" in the Multiple Button, Toggle Size and Cannot Be Dismissed popups and in XamlBindingPopupViewModel; it now reads "conform", as in ButtonPopup.
The Cannot Be Dismissed popup chose its description with OnPlatform for Android, iOS and WinUI only. OnPlatform has no iOS fallback for Mac Catalyst, so the label was empty there, and the WinUI text described the old Flyout-based popup ("Windows Flyouts do not have support for toggling light dismiss mode"), while the PopupPage-based popup keeps CanBeDismissedByTappingOutsideOfPopup = false on Windows too. The label now shows the one corrected description on every platform.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… instead of a misleading error (S-FILESAVER-CANCEL) After the fix for a canceled prompt (the previous commit), "Save using FileSaver from DI Container" still passed an empty file name to SaveAsync when the person pressed OK without typing one. On iOS the page then reported "File is not saved, Access to the path '<app>/tmp/<guid>' is denied." (RAN on the iOS 27 simulator): the library writes the file to a new temporary folder before the save UI opens, and an empty name names that folder. Mac Catalyst runs the same code (INFERRED). Android 36 opened the save UI with an empty name (RAN). An empty or blank name now shows the toast "File is not saved, the file name is empty" on every platform, and nothing is saved. A canceled prompt still ends the command without a toast. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the package before the save UI opens (S-FILESAVER-DOWNLOAD)
SaveFileInstance started the nuget.org download with HttpClient.GetStreamAsync before its try block and handed the open network stream to SaveAsync, which on Android reads it only after the person has chosen where to save. On Android (RAN on API 36 and 28 before this change):
- offline, the WebException of the download ("Unable to resolve host "www.nuget.org"") escaped the command and ended the app;
- when choosing the location took about 6 seconds, the saved file was incomplete (665,031 of 1,167,815 bytes), and the app then ended with a NetworkOnMainThreadException;
- after a canceled save, the app ended with a NetworkOnMainThreadException: `await using` disposed the unread response stream on the main thread, and Android's HTTP stack reads the rest of a response when its stream is closed.
The command now downloads the whole package with HttpClient.GetByteArrayAsync inside the try block and saves a MemoryStream of it. HttpClient reads the response to its end and disposes it itself, a failed download shows "File is not saved, <reason>" like a failed save, and the time spent in the save UI no longer matters. The ProgressBar is reset to 0 when a save starts, so that it shows this save's progress instead of the end of the previous one; on Android it now also advances during the save, because the library reports intermediate progress only for a stream that can seek.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e static button counts files only where System.IO sees them all (S-FOLDERPICKER)
"Pick Folder using static FolderPicker" counted the picked folder's files with Directory.EnumerateFiles(Folder.Path). On Android 10 and later, scoped storage keeps System.IO from listing files that other apps put in a shared folder, so the count was 0 for a DCIM folder holding 3 files (RAN on Android 36). The count is no longer shown there, and the alert says why. On Android 9 and earlier, iOS, Mac Catalyst and Windows the count is still shown, now inside a try block: a folder that the app is not allowed to list shows "Files count: not available, <reason>" instead of an exception escaping the command.
The results were long toasts, which Android 12 and later cut after two lines: "Folder picked: Name - Music, Path - /storage/emulated/0/Music, Files count …" (RAN on Android 36), and a longer path was cut even without the count. The three buttons now show the picked folder in an alert ("Folder picked", with "Name: …", "Path: …" and, for the static button, "Files count: …"), which shows the whole text on every platform. A canceled or failed pick still shows the toast "Folder is not picked, <reason>".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… anchored snackbar is visible and does not cover Back (S-SNACKBAR-MODAL) The modal page of SnackbarPage stacked "Display Snackbar" and "Back to Snackbar MainPage" at the top of the page, while the snackbar, which is anchored to "Display Snackbar", says that it is anchored to the button on the bottom. #2456 meant to move that button to the bottom; its last commit put both buttons in a VerticalStackLayout at the top. A snackbar anchored to a view appears above it. With the anchor at the top of the page: - Android 36 and 28: Material placed the snackbar above the anchor, outside the page; only a strip of it (API 36) or nothing (API 28) was visible. - iOS and Mac Catalyst: there was no room above the anchor, so AlertView placed the snackbar below it, over "Back to Snackbar MainPage" for its 5 seconds; clicks on Back did nothing until it went away. The buttons are now at the bottom of the modal page, "Display Snackbar" above "Back to Snackbar MainPage", so the snackbar appears above its anchor and Back stays visible and usable. The snackbar's text names the button it is anchored to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Color" instead of a missing glyph, and the page says what Windows does not apply (S-SNACKBAR-WINDOWS-GLYPH) The custom snackbar's action is the Font Awesome Microsoft logo, a private-use character drawn with ActionButtonFont. Windows shows a snackbar as an app notification, which draws its button text in the system font and does not use SnackbarOptions, so the button showed an empty box, and the red background, green text, corner radius and fonts did not appear either. On Windows the action is now the text "Change Color" (it gives "Display Custom Snackbar" a random color); the other platforms keep the glyph. The Windows note on the page says that the SnackbarOptions (colors, fonts, corner radius) and the anchor are not applied there. Its Grid row is Auto, so the longer note can wrap; on the other platforms, where the note is hidden, the row no longer leaves an empty 20-point band. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Page hide the page that opened them (S-ALERTS-MODAL-WINDOWS-TRANSPARENT) On Windows the implicit Page style of the Sample gives every Page a Transparent BackgroundColor, so that the Mica backdrop of the window shows through it. .NET MAUI on Windows removes the page below a modal page only when the modal page has no BackgroundColor and no Background; otherwise it keeps that page in the window. The modal pages of SnackbarPage and ToastPage are ContentPages, which the style also made Transparent, so SnackbarPage or ToastPage stayed visible under them: the modal page's buttons were drawn over the page's description text (SnackbarPage), and the buttons of the page below were still shown. These two modal pages have no BackgroundColor on Windows, so they replace the page below and show the Mica backdrop, like the modal NavigationPage of PopupsPage (the NavigationPage style sets no BackgroundColor). The other platforms keep the style's background. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stead of crashing the app (S-COLORANIM-RATE0) The page passed every Rate that uint.TryParse accepts to BackgroundColorTo and TextColorTo, 0 included. .NET MAUI's Tweener divides by the rate on every frame of the animation, so tapping Animate with Rate 0 ended the app with a DivideByZeroException thrown on the platform's animation ticker, where no try/catch of the page can catch it (iOS, and Android when the system animations are on). A Rate of 0 now falls back to the default of 16 ms, like text that is not a number already did, so the page never passes a rate the extension methods cannot animate with (with LIB-COLORANIM-RATE0 they throw an ArgumentOutOfRangeException for it, which would also end the app from the page's async void Clicked handler). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Android's gesture area (S-GRAVATAR-INSET) The page removes its own top and bottom padding so that its ScrollView fills the page, and the scrolled content had top padding only, so it ended with the Cache Validity Slider. On Android 15 and later the Sample is drawn edge to edge: scrolled to the end, the Slider's bottom edge touched the top of the navigation bar, and its lower part was inside the area at the bottom of the screen where Android takes system gestures. After the soft keyboard had been used (typing into the Email entry, then closing the keyboard with Back), the ScrollView kept less room or none for the navigation bar, and the Slider could end at the bottom edge of the screen, under the gesture handle, as reported (Android 36 emulator, gesture navigation). On Android the content now ends with 48 dp of bottom padding: the height of the three-button navigation bar, and more than the gesture area (32 dp on the Android 36 emulator), so the Slider stays clear of both even when the navigation bar inset is not applied. The other platforms keep their padding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ortedException of Mac Catalyst instead of doing nothing
KeyboardExtensions.IsSoftKeyboardShowing throws NotSupportedException on Mac Catalyst ("MacOS does not currently support opening the SoftKeyboard"), as ShowKeyboardAsync and HideKeyboardAsync do. The Show and Hide commands of the page catch it and show its message, but the IsKeyboardShowing command did not, so on Mac Catalyst the exception escaped the command and the label did not change (found in the qa-merged re-walk; the same code is on main). The command now shows the message like the other two.
RAN on Mac Catalyst (Debug, this change): Extensions > KeyboardExtensions > Check Keyboard State shows "MacOS does not currently support opening the SoftKeyboard".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ue corners instead of a 20x20 speck PopupOnDisappearingPage shows RedBlueBoxPopup without a size. Its content Grid fills the popup and holds four 10x10 blue squares at its corners, so a popup sized to its content is about 20x20: the corner squares lie on top of each other and the popup is easy to miss (seen on iOS 27 and Android 36 once the popup was displayed again by the Popup fix for a popup shown in OnDisappearing of a modal page). The popup now gets the 100x100 that the Popup Layout page gives the same popup by default, so it shows the red box with its four blue corner squares. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext is shown
After a failed load the text replaces the image (4c036f32), so the image leaves the tree, where an Element loses the BindingContext it inherits, and its ImageSource loses it too. A bound source then stopped following its view model: on GravatarImageSourcePage (GravatarImageSource Email="{Binding Email}"), clearing the Email showed the text (an empty Email does not load on Android), and typing an address afterwards never showed the photo again, while Image, Button and ImageButton showed it (Android 36).
The AvatarView now gives its image its own BindingContext (OnBindingContextChanged): a BindingContext that is set stays when the Element leaves the tree.
Unit tests: a bound image source follows its view model while the text is shown, and the image is shown once it loads; a new BindingContext reaches the image source while the text is shown (both fail without the fix). Device test: a StreamImageSource whose bound Stream changes from undecodable bytes to a red PNG after the failure shows the image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hile the handler maps the image A StreamImageSource whose stream is already there (a completed Task, as in the device test of the previous commit) fails its load synchronously. On Windows that happens inside BorderHandler.UpdateContent, which converts the image to its platform view and only then sets that view as the content of the border. AvatarView replaced Content with the text from inside the failure callback (DispatchIfRequired runs inline on the UI thread): the nested UpdateContent showed the label, and the outer one then put the image back. The Content of the AvatarView was the Label while the platform showed the empty image (RAN on the Windows 11 VM: ImageIsShownWhenABindingChangesTheImageSourceAfterAFailure failed in 3 of 3 runs with "The native content of the avatar is Image, expected Label"; a diagnostic run showed SourceFailedToLoad and Content = Label 18 ms after the attach started, before the handler was done). The text fallback of 4c036f32 had this from the start: ImageSource.FromStream opens its stream with Task.Run, so the earlier tests failed later and passed. AvatarView now posts both content changes to the dispatcher, so that they run after the handler's mapping, and a posted change applies only while the image still has the source whose load reported it. Device test: TextIsShownWhenTheImageSourceFailsAtOnce (AvatarView category). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comments that the Sample regression fixes, the round 3 StatusBar stream and the re-walk fixes brought in now say why, not what: comments that narrate the code or restate a test's name are gone (with every "Catches:" line that only restated its test), the XML docs of test helpers and of the private StatusBarView became short // comments where they carry a reason, and long comments keep only their reason. Only comments changed: the comment checker reports all 20 files comment-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nt change The comment above PostContentChange said that a load of an earlier source that reports after another source was set changes nothing. The handlers cannot tell that: they capture avatarImage.Source when the load reports, and .NET MAUI reports a failure without its source (IImageSourcePartEvents.LoadingFailed, also for a load that another source replaced). A failure that reports after the new source was set therefore counts for the new source. What the check does guarantee is that a change does nothing when the image gets another source between the report and the posted change, because setting ImageSource already chose the Content for that source. The comment now says that. Comment only: the comment checker reports the file comment-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and soft keyboard alone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s, so Android no longer hides the keyboard of the view the user moved to Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…SearchBar, whose focus MAUI tracks through its query editor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… dismissing behavior in a modal page or Popup also hides it while the page underneath has a focused Entry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
.NET MAUI reports the load of an empty image source (IsEmpty: a FileImageSource without a file, a UriImageSource without a Uri, a StreamImageSource without a stream, a GravatarImageSource without an Email) as a failure on Android, where the AvatarView has shown its text since 4c036f32, and as a success on iOS, Mac Catalyst and Windows, whose image source services return no image for an empty source. There the AvatarView kept the image and showed an empty circle. Brandon decided, on the finding of the Sample re-walk, that an empty image source counts as no image everywhere: when the load of an empty source is reported as a success, the text replaces the image. The image stays the Content until its load is reported, also for an empty source, because only an image that was shown has a handler that loads the source again when it stops being empty: a GravatarImageSource whose bound Email a person types still shows the photo. IImageSource.IsEmpty of the AvatarView is also true for an empty image source, and the remarks of ImageSource say so. Unit tests: the load of an empty File, Uri, Stream and Gravatar source shows the text; a source that gets a Uri shows the image; a loaded source that becomes empty shows the text; IImageSource.IsEmpty is true for an empty source (all fail without the change). Device tests (AvatarView category): empty File, Uri, Stream and Gravatar sources show the text; an empty source that a binding fills shows the image; a source that a binding empties shows the text. RAN (Debug) on the iOS 27 simulator, on Mac Catalyst and on Windows 11 (VM, unpackaged): without the change these 6 device tests fail with "The native content of the avatar is Image, expected Label"; with it they pass there and on Android 36. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he new source
.NET MAUI reports a failed load without the source that failed (IImageSourcePartEvents.LoadingFailed), also for a load that another source
replaced while it ran and that fails later, for example because it ignores its cancellation token and the server answers with an error. It also
clears the image view then, whichever load failed. The AvatarView took such a failure for the failure of the new source and replaced the image
with the text (the open edge case of the delivery review of 23c598cc: the text replaced the newer, valid image).
The AvatarView now tells the two apart with what .NET MAUI does report: LoadingStarted resets and LoadingCompleted(true) sets whether the current
load has succeeded. A failure that follows a success, with no load started in between, can only belong to a load that was replaced. .NET MAUI has
cleared the image of the new source, so the image loads again (UpdateValue of the Source) instead of the text replacing it. A failure that is
reported before the new source loaded still shows the text, until that source loads, because it cannot be told apart from the failure of the new
source itself. Each success covers one such failure, so a load that keeps failing cannot start loads in a loop.
Unit tests: the image loads again when a replaced load fails after the new source loaded (the handler is asked to update the Source); the image
shows when the new source loads after a replaced load failed; the text shows when a load fails after an earlier one succeeded (the first fails
without the change). Device test (AvatarView category): a StreamImageSource whose load ignores its token fails after a red image replaced it, and
the red image stays. RAN (Debug): without the change it fails on the iOS 27 simulator, on Mac Catalyst and on Windows 11 ("Pixel (50, 50) did
not get the color #FF0000", the text replaced the image); with it the test passes there and on Android 36.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…stead of being white on the light page With FillOption Background a RatingView paints every shape in EmptyShapeColor: the rated items on their FillColor background, the others on the transparent background of the RatingView. EmptyShapeColor was White on the review average, on the star of the trust review card, on the 4.9 review and on the negative review, so in the Light theme the stars of the unrated items were white on the white page (the card is white too) and could not be seen (found in the Sample re-walk on iOS and Android; the same on main). Brandon decided to make them theme aware. EmptyShapeColor of these four RatingViews is now an AppThemeBinding, Gray300 in Light and Gray500 in Dark, which also colors the stars on the green and red squares. The black border of the 4.9 review follows the theme as well (white in Dark, where black disappears into the page). The circles with a green border, the heart in the white Border and the golden stars are unchanged: they show in both themes already. RAN on the iOS 27 simulator (Debug) in Light and in Dark: every unrated star shows on the page and on the card in both themes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re, and a blank line between the nested test classes Review cleanup of f23e0565 and 4978c33d, comments and whitespace only (tools/comment-check: both files OK, no code token changed). The device test explained its fixed wait twice, on failureReportTimeout and again where it waits; the comment on the constant stays. RecordingViewHandler followed the nested AvatarViewModel without the blank line that separates the other members of the file. Unit tests (Debug, AvatarView classes): 67 of 67 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Light theme Gray300 on the light page is about 2.2:1, below the 3:1 contrast WCAG asks for graphics; Gray400 reaches 3:1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



This is a work in progress built upon @ne0rrmatrix’s work in #3277. It includes additional tests and additional bug fixes that the test discovered:
Fixes [BUG] Snackbar + UseMaterial3 overrides BackgroundColor [Android/Material3] #3307
Fixes [BUG] Crash occurs when a page transition occurs while displaying a Snackbar with an anchor specified on iOS #2827
Fixes The long press is triggered by multiple short taps #1818
Fixes [BUG] [Android] TouchBehavior alters the background color of its attached element unexpectedly #1826
Fixes [BUG] iOS: Slider unresponsive if parent view has TouchBehavior #2358
Fixes [BUG] [Android] Touch Effect registers 2 clicks in 1 on ImageButton. #1845
Fixes [BUG] TouchBehavior overrides BackgroundColor binding and prevents UI updates #3091
Fixes [BUG] DrawingView Error : PlatformView cannot be null here when used with BindableLayout (Android and iOS) #2320
Fixes [BUG] DrawingView Doesn't Clear Lines When Navigating Back to Screen B #2153
Fixes [BUG] [Android] DrawingView binding fails after switching tab #1879
Fixes [BUG] DrawingView does not render correctly after tab navigation (TabBar) #2078
Fixes [BUG] DrawingViewService.GetImageStream does not resize image stream correctly in WinUI #2570
Fixes [BUG] Android implementation of MediaElement raises unexpected Stopped state change when playing using AutoPlay #3079
Fixes [BUG] Potential memory leak in MediaElement on Windows #3113
Fixes [BUG] CameraView crashes Android application when going Back too soon #2900
Fixes [BUG] [Android] SpeechToText: StartListenAsync silently no-ops after auto-stop via silence detection #3212
Fixes [BUG] SIGABRT on iOS when Permissions.Camera not Granted #2519
Fixes [BUG] CameraView crashes if exited too quickly on Windows #3171
Fixes [BUG] App crash using Maui.Camera on Surface Go 2 and 3s (Windows) #3050
Fixes [BUG] Snackbar with Anchor not displayed on modal page #2734
Fixes [BUG] Toast randomly not dismissing in Windows #3014
Fixes [BUG] AvatarView not applying style from resources #3241
Fixes [BUG] Padding and Margin are not applied to the Popup class of Popup2 by Style attribute #2747
Fixes [BUG] UserStoppedTypingBehavior - ShouldDismissKeyboardAutomatically doesnt work on android #2230
Fixes [BUG] Calling CameraProvider.RefreshAvailableCameras() crashes on Android device with no cameras #2844
Fixes [BUG] DrawingView not rendering after navigating back to page #2889
Fixes [BUG] Possible memory leak on IconTintColorBehavior.macios #2015
Fixes [BUG] IconTintColorBehavior not applying tint to Buttons with images on Android and Windows #2040
Fixes [BUG] [Andriod][FileSaver] Crash when removing USB drive #1588
Fixes [BUG] IndexToArrayItemConverter CTD #2404
Fixes DrawingView.GetImageStream Size has no affect #1397
Fixes [BUG] Android 14+ Notification Body Tap Does Nothing #2976
Fixes [BUG] Setting StatusBarBehavior breaks it on iOS in landscape mode #1707
Fixes [BUG] StatusBarBehavior causes weird rect overlay on iOS on rotation #3210
Fixes [BUG] Multiple issues with AvatarView/GravatarImageSource #1732
Fixes [BUG] Android 35+: NavigationBar.SetColor has no effect #3056
Fixes [BUG] NavigationBar of AndroidSpecific Color proprerty is not working on Android 16 #3008
Fixes [BUG] Map not responding to span (zoom) requests in Windows #1686
Created a new project for device tests with necessary configurations.
Implemented an in-app test runner to execute xUnit tests within the MAUI application.
Added various test classes to verify platform-specific behaviors, including handler creation and platform detection.
Configured the application to display a message while tests are running.
Included platform-specific entry points and manifest files for Android, iOS, MacCatalyst, and Windows.
Added resources for app icons and splash screens.
Documented the project structure and instructions for running tests locally in the README.
Partially Fixed (will be finished in a future PR): #3317, #2894, #2691, #3063, #2952, #1987, #2645, #3220, #3248, #2602
Partially Fixed (already closed, will be finished with #3317): #2383, #2950