Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Testing] Added a support for the device's theme change #22508

Merged
merged 20 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/ThemeChange.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?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"
Title="ThemeChange"
x:Class="Maui.Controls.Sample.Issues.ThemeChange">
<VerticalStackLayout>
<Label Text="Text visible only in dark mode" AutomationId="labelVisibleOnlyInDarkMode" IsVisible="{AppThemeBinding Dark=True, Light=False}"/>
<Label Text="Text visible only in light mode" AutomationId="labelVisibleOnlyInLightMode" IsVisible="{AppThemeBinding Dark=False, Light=True}"/>
</VerticalStackLayout>
</ContentPage>
15 changes: 15 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/ThemeChange.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;

namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.None, 2, "UI theme change during the runtime", PlatformAffected.Android | PlatformAffected.iOS)]
public partial class ThemeChange : ContentPage
{
public ThemeChange()
{
InitializeComponent();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#if ANDROID || IOS
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class ThemeChange : _IssuesUITest
{
public override string Issue => "UI theme change during the runtime";

public ThemeChange(TestDevice device) : base(device)
{
}

[Test]
[Category(UITestCategories.LifeCycle)]
jfversluis marked this conversation as resolved.
Show resolved Hide resolved
public void AppThemeShouldChange()
{
try
{
App.SetLightTheme();
_ = App.WaitForElement("labelVisibleOnlyInLightMode");

App.SetDarkTheme();
_ = App.WaitForElement("labelVisibleOnlyInDarkMode");
VerifyScreenshot("AppThemeShouldChangeDarkTheme");

App.SetLightTheme();
_ = App.WaitForElement("labelVisibleOnlyInLightMode");
VerifyScreenshot("AppThemeShouldChangeLightTheme");
}
finally
{
App.SetLightTheme();
}
}
}
}
#endif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.Diagnostics;
using UITest.Core;

namespace UITest.Appium
{
public class AppiumAndroidThemeChangeAction : ICommandExecutionGroup
{
const string SetLightTheme = "setLightTheme";
const string SetDarkTheme = "setDarkTheme";

readonly List<string> _commands = new()
{
SetLightTheme,
SetDarkTheme
};

public CommandResponse Execute(string commandName, IDictionary<string, object> parameters)
{
if (commandName == SetLightTheme)
kubaflo marked this conversation as resolved.
Show resolved Hide resolved
{
ExecuteAdbCommand($"adb shell cmd uimode night no");
kubaflo marked this conversation as resolved.
Show resolved Hide resolved
return CommandResponse.SuccessEmptyResponse;
}
else if (commandName == SetDarkTheme)
{
ExecuteAdbCommand($"adb shell cmd uimode night yes");
return CommandResponse.SuccessEmptyResponse;
}

return CommandResponse.FailedEmptyResponse;
}

public bool IsCommandSupported(string commandName)
{
return _commands.Contains(commandName, StringComparer.OrdinalIgnoreCase);
}

private static void ExecuteAdbCommand(string command)
{
var shell = GetShell();
var shellArgument = GetShellArgument(shell, command);

var processInfo = new ProcessStartInfo(shell, shellArgument)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};

var process = new Process { StartInfo = processInfo };

process.Start();
process.WaitForExit();
}

private static string GetShell()
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
return "cmd.exe";
else
return "/bin/bash";
}

private static string GetShellArgument(string shell, string command)
{
if (shell == "cmd.exe")
return $"/C {command}";
else
return $"-c \"{command}\"";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Diagnostics;
using UITest.Core;

namespace UITest.Appium
{
public class AppiumIOSThemeChangeAction : ICommandExecutionGroup
{
const string SetLightTheme = "setLightTheme";
const string SetDarkTheme = "setDarkTheme";

protected readonly AppiumApp _app;

public AppiumIOSThemeChangeAction(AppiumApp app)
{
_app = app;
}

readonly List<string> _commands = new()
{
SetLightTheme,
SetDarkTheme
};

public CommandResponse Execute(string commandName, IDictionary<string, object> parameters)
{
if (commandName == SetLightTheme)
{
var args = new Dictionary<string, string> { { "style", "light" } };
_app.Driver.ExecuteScript("mobile: setAppearance", args);
return CommandResponse.SuccessEmptyResponse;
}
else if(commandName == SetDarkTheme)
{
var args = new Dictionary<string, string> { { "style", "dark" } };
_app.Driver.ExecuteScript("mobile: setAppearance", args);
return CommandResponse.SuccessEmptyResponse;
}

return CommandResponse.FailedEmptyResponse;
}

public bool IsCommandSupported(string commandName)
{
return _commands.Contains(commandName, StringComparer.OrdinalIgnoreCase);
}
}
}

1 change: 1 addition & 0 deletions src/TestUtils/src/UITest.Appium/AppiumAndroidApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class AppiumAndroidApp : AppiumApp, IAndroidApp
private AppiumAndroidApp(Uri remoteAddress, IConfig config)
: base(new AndroidDriver(remoteAddress, GetOptions(config)), config)
{
_commandExecutor.AddCommandGroup(new AppiumAndroidThemeChangeAction());
_commandExecutor.AddCommandGroup(new AppiumAndroidVirtualKeyboardActions(this));
_commandExecutor.AddCommandGroup(new AppiumAndroidAlertActions(this));
}
Expand Down
2 changes: 2 additions & 0 deletions src/TestUtils/src/UITest.Appium/AppiumIOSApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public AppiumIOSApp(Uri remoteAddress, IConfig config)
_commandExecutor.AddCommandGroup(new AppiumIOSMouseActions(this));
_commandExecutor.AddCommandGroup(new AppiumIOSTouchActions(this));
_commandExecutor.AddCommandGroup(new AppiumIOSVirtualKeyboardActions(this));
_commandExecutor.AddCommandGroup(new AppiumIOSThemeChangeAction(this));
_commandExecutor.AddCommandGroup(new AppiumIOSAlertActions(this));
_commandExecutor.AddCommandGroup(new AppiumIOSThemeChangeAction(this));
}

public override ApplicationState AppState
Expand Down
28 changes: 28 additions & 0 deletions src/TestUtils/src/UITest.Appium/HelperExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,34 @@ public static TestDevice GetTestDevice(this IApp app)
return aaa.Config.GetProperty<TestDevice>("TestDevice");
}

/// <summary>
/// Sets light device's theme
/// </summary>
/// <param name="app">Represents the main gateway to interact with an app.</param>
public static void SetLightTheme(this IApp app)
{
if (app is not AppiumAndroidApp && app is not AppiumIOSApp)
{
throw new InvalidOperationException($"SetLightTheme is not supported");
}

app.CommandExecutor.Execute("setLightTheme", ImmutableDictionary<string, object>.Empty);
kubaflo marked this conversation as resolved.
Show resolved Hide resolved
}

/// <summary>
/// Sets dark device's theme
/// </summary>
/// <param name="app">Represents the main gateway to interact with an app.</param>
public static void SetDarkTheme(this IApp app)
kubaflo marked this conversation as resolved.
Show resolved Hide resolved
{
if (app is not AppiumAndroidApp && app is not AppiumIOSApp)
{
throw new InvalidOperationException($"SetDarkTheme is not supported");
}

app.CommandExecutor.Execute("setDarkTheme", ImmutableDictionary<string, object>.Empty);
}

/// <summary>
/// Check if element has focused
/// </summary>
Expand Down
Loading