Files
MBN_STOCK_WEBVIEW/tests/MBN_STOCK_WEBVIEW.LegacyWeb.Tests/LegacyStartupIntroNativeContractTests.cs
Wickedness b050f2f06c feat: refine branded operator experience
Add the MBN-branded startup intro, semantic sidebar icons, and refined card-based operator visuals. Strengthen packaged UI and input smoke coverage for the updated experience.
2026-07-24 01:26:13 +09:00

243 lines
8.9 KiB
C#

using System.Buffers.Binary;
namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;
public sealed class LegacyStartupIntroNativeContractTests
{
private static readonly string RepositoryRoot = FindRepositoryRoot();
private static readonly string AppRoot = Path.Combine(
RepositoryRoot,
"src",
"MBN_STOCK_WEBVIEW.LegacyParityApp");
private static readonly string WindowXaml = File.ReadAllText(
Path.Combine(AppRoot, "MainWindow.xaml"));
private static readonly string Window = File.ReadAllText(
Path.Combine(AppRoot, "MainWindow.xaml.cs"));
private static readonly string StartupIntro = File.ReadAllText(
Path.Combine(AppRoot, "MainWindow.StartupIntro.cs"));
private static readonly string Manifest = File.ReadAllText(
Path.Combine(AppRoot, "Package.appxmanifest"));
private static readonly string Project = File.ReadAllText(
Path.Combine(AppRoot, "MBN_STOCK_WEBVIEW.LegacyParityApp.csproj"));
[Fact]
public void IntroUsesOnlyPackagedBrandAssetsAndCompactCopy()
{
var overlay = Slice(
WindowXaml,
"x:Name=\"LoadingOverlay\"",
"<InfoBar");
Assert.Contains(
"ms-appx:///Assets/Square150x150Logo.scale-200.png",
overlay,
StringComparison.Ordinal);
Assert.Contains(
"ms-appx:///Assets/StartupHero.png",
overlay,
StringComparison.Ordinal);
Assert.Contains(
"ms-appx:///Web/Brand/logo.png",
overlay,
StringComparison.Ordinal);
Assert.Contains("V-STOCK", overlay, StringComparison.Ordinal);
Assert.Contains("증권정보 송출 시스템", overlay, StringComparison.Ordinal);
Assert.DoesNotContain("http://", overlay, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("https://", overlay, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("원본 호환 화면을 준비하고 있습니다.", overlay,
StringComparison.Ordinal);
}
[Fact]
public void GeneratedBroadcastHeroIsAProjectPackagedWidePng()
{
const string heroInclude =
"<Content Include=\"..\\..\\Assets\\StartupHero.png\" Link=\"Assets\\StartupHero.png\" />";
Assert.Contains(heroInclude, Project, StringComparison.Ordinal);
var heroPath = Path.Combine(RepositoryRoot, "Assets", "StartupHero.png");
var bytes = File.ReadAllBytes(heroPath);
Assert.True(bytes.Length > 500_000);
Assert.Equal(
new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 },
bytes[..8]);
Assert.True(bytes.Length >= 24);
var width = BinaryPrimitives.ReadInt32BigEndian(bytes.AsSpan(16, 4));
var height = BinaryPrimitives.ReadInt32BigEndian(bytes.AsSpan(20, 4));
Assert.True(width >= 1600);
Assert.True(height >= 900);
Assert.True((double)width / height > 1.7);
}
[Fact]
public void IntroUsesTheDeepNavyMbnAccentAndShortNativeMotion()
{
var overlay = Slice(
WindowXaml,
"x:Name=\"LoadingOverlay\"",
"<InfoBar");
Assert.Contains("#FF08182B", WindowXaml, StringComparison.OrdinalIgnoreCase);
Assert.Contains("#FFF47B20", overlay, StringComparison.OrdinalIgnoreCase);
Assert.Contains(
"x:Name=\"StartupIntroEnterStoryboard\"",
WindowXaml,
StringComparison.Ordinal);
Assert.Contains(
"x:Name=\"StartupIntroExitStoryboard\"",
WindowXaml,
StringComparison.Ordinal);
Assert.Contains("IsIndeterminate=\"True\"", overlay, StringComparison.Ordinal);
Assert.Contains(
"AutomationProperties.Name=\"매일경제TV V-STOCK 시작 화면\"",
overlay,
StringComparison.Ordinal);
Assert.Contains(
"AutomationProperties.AccessibilityView=\"Content\"",
overlay,
StringComparison.Ordinal);
}
[Fact]
public void EveryStartupOutcomeKeepsItsCancellableTwoSecondHold()
{
Assert.Contains(
"TimeSpan.FromMilliseconds(2050)",
StartupIntro,
StringComparison.Ordinal);
Assert.Contains(
"TimeSpan.FromMilliseconds(180)",
StartupIntro,
StringComparison.Ordinal);
Assert.Contains("UISettings", StartupIntro, StringComparison.Ordinal);
Assert.Contains(".AnimationsEnabled", StartupIntro, StringComparison.Ordinal);
Assert.Contains(
"Interlocked.CompareExchange(",
StartupIntro,
StringComparison.Ordinal);
Assert.Contains(
"_lifetimeCancellation.Token",
StartupIntro,
StringComparison.Ordinal);
Assert.Contains("Task.Delay(", StartupIntro, StringComparison.Ordinal);
Assert.DoesNotContain(
"skipMinimumDuration",
StartupIntro,
StringComparison.Ordinal);
Assert.Contains(
"if (!_startupIntroAnimationsEnabled)",
StartupIntro,
StringComparison.Ordinal);
}
[Fact]
public void WebReadyPostsTheFirstStateBeforeEveryOutcomeUsesTheSameDismissal()
{
var dispatch = Slice(
Window,
"private async Task ProcessIntentAsync(",
"private static bool IsNamedPlaylistModalIntent(");
var finalPost = RequiredIndex(dispatch, "PostState(state);");
var readyDismiss = RequiredIndex(
dispatch,
"if (intent is LegacyReadyIntent)",
finalPost);
var normalDismiss = RequiredIndex(
dispatch,
"BeginDismissStartupIntro();",
readyDismiss);
Assert.True(finalPost < readyDismiss);
Assert.True(readyDismiss < normalDismiss);
var failurePost = RequiredIndex(dispatch, "PostState(failureState);");
var immediateDismiss = RequiredIndex(
dispatch,
"BeginDismissStartupIntro();",
failurePost);
Assert.True(failurePost < immediateDismiss);
var navigation = Slice(
Window,
"private void OnNavigationCompleted(",
"private static void OnNewWindowRequested(");
Assert.Contains("if (!args.IsSuccess)", navigation, StringComparison.Ordinal);
Assert.Contains(
"BeginDismissStartupIntro();",
navigation,
StringComparison.Ordinal);
Assert.DoesNotContain(
"LoadingOverlay.Visibility = Visibility.Collapsed;",
navigation,
StringComparison.Ordinal);
}
[Fact]
public void IntroBlocksInputUntilItsOneShotDismissalCompletes()
{
var browser = Slice(WindowXaml, "<WebView2", "/>");
Assert.Contains("x:Name=\"Browser\"", browser, StringComparison.Ordinal);
Assert.Contains("IsHitTestVisible=\"False\"", browser, StringComparison.Ordinal);
Assert.Contains(
"LoadingOverlay.Visibility = Visibility.Collapsed;",
StartupIntro,
StringComparison.Ordinal);
Assert.Contains(
"LoadingOverlay.IsHitTestVisible = false;",
StartupIntro,
StringComparison.Ordinal);
Assert.Contains(
"Browser.IsHitTestVisible = true;",
StartupIntro,
StringComparison.Ordinal);
var loaded = Slice(
Window,
"private async void OnRootLoaded(",
"private void ConfigureWindow()");
Assert.Contains("StartStartupIntro();", loaded, StringComparison.Ordinal);
}
[Fact]
public void MsixSystemSplashMatchesTheNativeIntroCanvas()
{
Assert.Contains(
"BackgroundColor=\"#08182B\"",
Manifest,
StringComparison.OrdinalIgnoreCase);
Assert.Contains(
"<uap:SplashScreen Image=\"Assets\\SplashScreen.png\" />",
Manifest,
StringComparison.Ordinal);
}
private static string Slice(string value, string start, string end)
{
var startIndex = RequiredIndex(value, start);
var endIndex = RequiredIndex(value, end, startIndex + start.Length);
return value[startIndex..endIndex];
}
private static int RequiredIndex(string value, string needle, int startIndex = 0)
{
var index = value.IndexOf(needle, startIndex, StringComparison.Ordinal);
Assert.True(index >= 0, $"Required marker was not found: {needle}");
return index;
}
private static string FindRepositoryRoot()
{
var directory = new DirectoryInfo(AppContext.BaseDirectory);
while (directory is not null)
{
if (File.Exists(Path.Combine(directory.FullName, "MBN_STOCK_WEBVIEW.sln")))
{
return directory.FullName;
}
directory = directory.Parent;
}
throw new DirectoryNotFoundException("Repository root was not found.");
}
}