Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
46bbbfe
WIP: iOS integration test
jpnurmi Sep 24, 2025
43b57c7
Split common.ps1 vs. setup.ps1
jpnurmi Sep 24, 2025
d79436c
Fix empty --device argument
jpnurmi Sep 24, 2025
a916900
Temp speed up
jpnurmi Sep 24, 2025
67fd410
Try BeforeAll
jpnurmi Sep 24, 2025
83c3084
Restore, retry, artifacts
jpnurmi Sep 24, 2025
6cc7696
Add test/Sentry.Maui.Device.IntegrationTestApp
jpnurmi Sep 24, 2025
abdc057
Update solution filter
jpnurmi Sep 24, 2025
7ac73d0
Speed up
jpnurmi Sep 25, 2025
adf7b68
Partial revert
jpnurmi Sep 25, 2025
e190195
Managed vs. Native vs. NullRefenceException
jpnurmi Sep 25, 2025
aff8901
Fixup
jpnurmi Sep 25, 2025
29bef65
Move to integration-test/ios.Tests.ps1
jpnurmi Sep 25, 2025
2c516c2
Fixup
jpnurmi Sep 25, 2025
30b08fd
Use shared Install-XHarness
jpnurmi Sep 25, 2025
6389645
Fix Install-XHarness
jpnurmi Sep 25, 2025
44a190e
Add RunTestApp helper func
jpnurmi Sep 25, 2025
26e6d05
Fix Install-XHarness - attempt 2
jpnurmi Sep 25, 2025
5f6eb95
Prefer booted sims
jpnurmi Sep 25, 2025
28a57ae
Convert tabs to spaces
jpnurmi Sep 25, 2025
ba70ab2
Fix PreferredStates
jpnurmi Sep 25, 2025
64d2827
Fix Install-XHarness
jpnurmi Sep 25, 2025
90cda33
Rename to mobile.Tests.ps1 and prepare iOS context
jpnurmi Sep 25, 2025
c58bd4f
Leave scripts/device-test-utils.ps1 in the sparse checkout for integr…
jpnurmi Sep 25, 2025
5e01b48
Add missing timeout
jpnurmi Sep 25, 2025
8121c4c
Fix Android tfm
jpnurmi Sep 25, 2025
d508359
Prepare predictable Activity name on Android
jpnurmi Sep 25, 2025
76eeddf
Fix path
jpnurmi Sep 25, 2025
4931fcb
Add missing continue-on-error: true
jpnurmi Sep 25, 2025
f438a74
Apply suggestions from code review
jpnurmi Sep 26, 2025
459508a
Move the app to integration-test/mobile-app
jpnurmi Sep 26, 2025
24646df
restore ios 18.5
jpnurmi Sep 26, 2025
9b924e3
MSBUILD : error MSB1009: Project file does not exist.
jpnurmi Sep 26, 2025
ad8f805
.gitignore :x
jpnurmi Sep 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ jobs:
# integration tests, e.g. Directory.Build.props, nuget.config, ...
sparse-checkout: |
integration-test
scripts
.github

- name: Fetch NuGet Packages
Expand Down
21 changes: 18 additions & 3 deletions .github/workflows/device-tests-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,32 @@ jobs:
run: pwsh ./scripts/device-test.ps1 ios -Build

- name: Run Tests
id: first-run
id: first-test-run
continue-on-error: true
run: pwsh scripts/device-test.ps1 ios -Run

- name: Retry Tests (if previous failed to run)
if: steps.first-run.outcome == 'failure'
if: steps.first-test-run.outcome == 'failure'
run: pwsh scripts/device-test.ps1 ios -Run

- name: Run Integration Tests
id: first-integration-test-run
continue-on-error: true
uses: getsentry/github-workflows/sentry-cli/integration-test/@a5e409bd5bad4c295201cdcfe862b17c50b29ab7 # v2.14.1
with:
path: integration-test/mobile.Tests.ps1

- name: Retry Integration Tests (if previous failed to run)
if: steps.first-integration-test-run.outcome == 'failure'
uses: getsentry/github-workflows/sentry-cli/integration-test/@a5e409bd5bad4c295201cdcfe862b17c50b29ab7 # v2.14.1
with:
path: integration-test/mobile.Tests.ps1

- name: Upload results
if: success() || failure()
uses: actions/upload-artifact@v4
with:
name: device-test-ios-results
path: test_output
path: |
test_output
integration_test_output
52 changes: 1 addition & 51 deletions integration-test/common.ps1
Original file line number Diff line number Diff line change
@@ -1,54 +1,4 @@
# So that this works in VS Code testing integration. Otherwise the script is run within its directory.

# In CI, the module is loaded automatically
if (!(Test-Path env:CI ))
{
Import-Module $PSScriptRoot/../../github-workflows/sentry-cli/integration-test/action.psm1 -Force
}

function ShouldAnyElementMatch ($ActualValue, [string]$ExpectedValue, [switch] $Negate, [string] $Because)
{
<#
.SYNOPSIS
Asserts whether any item in the collection matches the expected value
.EXAMPLE
'foo','bar','foobar' | Should -AnyElementMatch 'oob'

This should pass because 'oob' is a substring of 'foobar'.
#>

$filtered = $ActualValue | Where-Object { $_ -match $ExpectedValue }
[bool] $succeeded = @($filtered).Count -gt 0
if ($Negate) { $succeeded = -not $succeeded }

if (-not $succeeded)
{
if ($Negate)
{
$failureMessage = "Expected string '$ExpectedValue' to match no elements in collection @($($ActualValue -join ', '))$(if($Because) { " because $Because"})."
}
else
{
$failureMessage = "Expected string '$ExpectedValue' to match any element in collection @($($ActualValue -join ', '))$(if($Because) { " because $Because"})."
}
}
else
{
$failureMessage = $null
}

return [pscustomobject]@{
Succeeded = $succeeded
FailureMessage = $failureMessage
}
}

BeforeDiscovery {
Add-ShouldOperator -Name AnyElementMatch `
-InternalName 'ShouldAnyElementMatch' `
-Test ${function:ShouldAnyElementMatch} `
-SupportsArrayInput
}
. $PSScriptRoot/pester.ps1

AfterAll {
Pop-Location
Expand Down
14 changes: 14 additions & 0 deletions integration-test/mobile-app/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Sentry.Maui.Device.IntegrationTestApp"
x:Class="Sentry.Maui.Device.IntegrationTestApp.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
14 changes: 14 additions & 0 deletions integration-test/mobile-app/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Sentry.Maui.Device.IntegrationTestApp;

public partial class App : Application
{
public App()
{
InitializeComponent();
}

protected override Window CreateWindow(IActivationState? activationState)
{
return new Window(new AppShell());
}
}
14 changes: 14 additions & 0 deletions integration-test/mobile-app/AppShell.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="Sentry.Maui.Device.IntegrationTestApp.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Sentry.Maui.Device.IntegrationTestApp"
Title="Sentry.Maui.Device.IntegrationTestApp">

<ShellContent
Title="Home"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />

</Shell>
9 changes: 9 additions & 0 deletions integration-test/mobile-app/AppShell.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Sentry.Maui.Device.IntegrationTestApp;

public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
}
}
2 changes: 2 additions & 0 deletions integration-test/mobile-app/GlobalXmlns.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[assembly: XmlnsDefinition("http://schemas.microsoft.com/dotnet/maui/global", "Sentry.Maui.Device.IntegrationTestApp")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/dotnet/maui/global", "Sentry.Maui.Device.IntegrationTestApp.Pages")]
29 changes: 29 additions & 0 deletions integration-test/mobile-app/MainPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Sentry.Maui.Device.IntegrationTestApp.MainPage">

<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Image
Source="dotnet_bot.png"
HeightRequest="185"
Aspect="AspectFit"
SemanticProperties.Description="dot net bot in a hovercraft number nine" />

<Label
Text="Hello, World!"
Style="{StaticResource Headline}"
SemanticProperties.HeadingLevel="Level1" />

<Label
Text="Welcome to &#10;.NET Multi-platform App UI"
Style="{StaticResource SubHeadline}"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I" />
</VerticalStackLayout>
</ScrollView>

</ContentPage>
39 changes: 39 additions & 0 deletions integration-test/mobile-app/MainPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
namespace Sentry.Maui.Device.IntegrationTestApp;

public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}

protected override void OnAppearing()
{
base.OnAppearing();

#pragma warning disable CS0618
var crashTypeEnv = Environment.GetEnvironmentVariable("SENTRY_CRASH_TYPE");
if (Enum.TryParse<CrashType>(crashTypeEnv, ignoreCase: true, out var crashType))
{
SentrySdk.CauseCrash(crashType);
}
#pragma warning restore CS0618

var testActionEnv = Environment.GetEnvironmentVariable("SENTRY_TEST_ACTION");
if (testActionEnv?.Equals("NullReferenceException", StringComparison.OrdinalIgnoreCase) == true)
{
try
{
object? obj = null;
_ = obj!.ToString();
}
catch (NullReferenceException ex)
{
SentrySdk.CaptureException(ex);
}
}

SentrySdk.Flush();
Environment.Exit(0);
}
}
30 changes: 30 additions & 0 deletions integration-test/mobile-app/MauiProgram.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.Extensions.Logging;
using Sentry.Maui;

namespace Sentry.Maui.Device.IntegrationTestApp;

public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseSentry(options =>
{
options.Debug = true;
options.DiagnosticLevel = SentryLevel.Info;
})
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});

#if DEBUG
builder.Logging.AddDebug();
#endif

return builder.Build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
16 changes: 16 additions & 0 deletions integration-test/mobile-app/Platforms/Android/MainActivity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Android.App;
using Android.Content.PM;
using Android.OS;

namespace Sentry.Maui.Device.IntegrationTestApp;

[Activity(
Name = "io.sentry.dotnet.maui.device.integrationtestapp.MainActivity",
Theme = "@style/Maui.SplashTheme",
MainLauncher = true,
LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density
)]
public class MainActivity : MauiAppCompatActivity
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Android.App;
using Android.Runtime;

namespace Sentry.Maui.Device.IntegrationTestApp;

[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}

protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#512BD4</color>
<color name="colorPrimaryDark">#2B0B98</color>
<color name="colorAccent">#2B0B98</color>
</resources>
9 changes: 9 additions & 0 deletions integration-test/mobile-app/Platforms/iOS/AppDelegate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Foundation;

namespace Sentry.Maui.Device.IntegrationTestApp;

[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
32 changes: 32 additions & 0 deletions integration-test/mobile-app/Platforms/iOS/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/appicon.appiconset</string>
</dict>
</plist>
15 changes: 15 additions & 0 deletions integration-test/mobile-app/Platforms/iOS/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using ObjCRuntime;
using UIKit;

namespace Sentry.Maui.Device.IntegrationTestApp;

public class Program
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, typeof(AppDelegate));
}
}
Loading
Loading