feat(source): show literal snapshots beside the reader
Persist source visibility and width, refresh the committed snapshot on reload, and keep the reader usable with both panes open. Add hosted literal/read-only/reload acceptance and opt-in native event traces for the two outstanding pointer failures. Refs: #8, #9, #10 Co-Authored-By: Codex (GPT-6) <noreply@openai.com> Signed-off-by: James Maes <jmaes@dmdbrands.com>
This commit is contained in:
13 files changed
+243
-8
No files matched your search
@@ -34,6 +34,7 @@ Prerelease tags (`v1.2.3-beta.1`) publish to the `dev` channel
|
||||
- **View → Document theme:** choose one of Darin's 20 built-in palettes. The saved document palette is independent of the Windows shell theme; changing it retains the reading position.
|
||||
- **View → Edit document theme:** edit colors, code font/size and custom CSS. Keep its name to override a built-in, or enter a new name to create a custom theme. Invalid input keeps the editor open. **Restore built-in themes** removes built-in edits after confirmation and keeps separately named custom themes.
|
||||
- **View → Table of contents:** show the heading sidebar, choose levels 1–6, and drag its divider to resize. Select a heading to jump there; collapse a selected section or all sections, then expand when ready. Matching section state survives reloads and document theme changes.
|
||||
- **View → Markdown source:** show the literal, read-only snapshot beside the reader, including frontmatter and fenced code. Visibility and preferred divider width persist; saves refresh both surfaces. Heading/scroll synchronization and paired find remain in development.
|
||||
- **View → Frontmatter:** hide leading YAML by default, show an escaped metadata table, or render the block as Markdown. The mode is saved and applied to reloads.
|
||||
- **View:** choose the light, dark, or system shell theme; turn the startup splash and the
|
||||
startup update check on or off. Choices are saved immediately.
|
||||
|
||||
@@ -99,3 +99,24 @@ before production publication; active Azure profiles do not prove successful sig
|
||||
|
||||
Pinned reference: 6d08bc9d27d7d7b2c2fa95bb282da330b8cf9021 under
|
||||
AppKit/artifacts/markdownviewr-reference. Preserve original MIT attribution on adaptations.
|
||||
|
||||
## Literal source and precise native event follow-up
|
||||
|
||||
Latest prior head d59dba2c96d126730f491720fd548c43c30dd97b: CI 38105483808
|
||||
terminal FAILURE (31/33 loose native/UI); CodeQL 38105483850 and scripts
|
||||
38105483489 SUCCESS. Mouse down/up settling did not solve the two input cases.
|
||||
Retained log: artifacts/pointer-states-ui-38105483808.log. No local GUI input.
|
||||
|
||||
Issue #10 records the full source/sync/find/keys acceptance. The next implementation
|
||||
adds a native read-only literal source pane (including hidden frontmatter), persisted
|
||||
visibility/preferred width, both-side width bounds and the same committed reload snapshot.
|
||||
This does not complete synchronized headings/scroll/collapse, paired find or vim keys.
|
||||
The browser's scripts/messages/host objects remain disabled. New actual UI test checks
|
||||
literal hostile source, read-only state, saved settings, reload and hiding.
|
||||
166 core tests/100% line coverage, zero-warning build and formatting pass locally.
|
||||
Hosted acceptance and physical source resize remain required.
|
||||
|
||||
Fixture-only MARKDOWNVIEWR_INPUT_TRACE=1 records native pressed/released/capture-lost,
|
||||
outline drag events and frontmatter clicks without changing routing or logging content.
|
||||
This tests whether WinUI receives the exact physical events; no third timing workaround
|
||||
or weakened outcome assertion. The next exact hosted handles must be observed.
|
||||
+7
-3
@@ -19,11 +19,15 @@
|
||||
- [x] Implement persistent resizable TOC/depth, safe heading/local-fragment jumps and independent nested section collapse (issue #9).
|
||||
- [x] Verify hosted heading jumps, independent nested collapse and theme/reload state on 5c3988e (31/33 UI pass).
|
||||
- [ ] Verify physical sidebar resize and frontmatter input follow-up; keep exact assertions.
|
||||
- [ ] Add source pane, synchronized navigation, find and vim keys.
|
||||
- [x] Implement literal read-only source pane, saved visibility/width and shared committed reload snapshots (issue #10).
|
||||
- [ ] Verify hosted source visibility/read-only/literal/reload acceptance and physical source resize.
|
||||
- [ ] Add synchronized headings/scroll/collapse, paired find and vim keys (issue #10).
|
||||
- [x] Implement and core-test hidden/metadata/Markdown frontmatter modes, with persisted native controls and attribution.
|
||||
- [ ] Verify actual hosted frontmatter mode switching and code-font size editing.
|
||||
- [x] Verify actual code-font size 17 editing in hosted UI runs.
|
||||
- [ ] Verify actual hosted frontmatter mode switching.
|
||||
- [ ] Add safe configured editor launch and printing options.
|
||||
- [ ] Add multiple document windows, recent files and Windows activation/file associations.
|
||||
- [ ] Verify hosted checks on each actual implementation head; PSScriptAnalyzer engine crash remains tracked in #5.
|
||||
- [x] Verify the all-rule two-pass PSScriptAnalyzer mitigation on scripts 38104988748 and 38105483489; closes #5 only on reviewed merge.
|
||||
- [ ] Verify hosted checks on each actual implementation head.
|
||||
- [ ] Finish standards inventory and reviewed/published AppKit/signing API adoption when available.
|
||||
- [ ] Verify actual signed stable/dev installers and exact shipped bytes before release publication.
|
||||
@@ -25,6 +25,8 @@ physical directory. It does not authorize native commands or remote resource acc
|
||||
| File change notifications | Directory subscription scoped to selected path; 350 ms quiet-period debounce; replacement/deletion recovery; bounded transient retries; subscriptions released on window close |
|
||||
| Theme JSON / CSS | Native editor and saved user overrides use the same bounded validation; corrupt theme settings are discarded before startup; restoration keeps separately named custom themes; embedded original palettes; bounded schema-version-one parser; validated hex colors and finite sizes; code-point escaped font names; less-than signs escaped before style embedding; no network capability |
|
||||
| Browser viewport | Fixed origin-checked native query; validate two finite fractions; invariant numeric restore only; authored scripts/messages stay disabled |
|
||||
| Source pane | Same bounded committed snapshot in a native read-only TextBox; literal HTML/CSS/script text never enters a renderer or command interpreter; hidden pane removed from accessibility surface |
|
||||
| Fixture input diagnostics | Explicit opt-in environment switch; observes handled native pointer/drag events without changing routing; logs owned control names, coordinates and button state only, never document text or keystrokes |
|
||||
| Browser surface | Scripts, messages, host objects, permissions, downloads, frames and popups disabled; restrictive CSP |
|
||||
| Local images | Per-document URI prefix; one decode; filename/extension policy; final open-handle containment; 16 MiB limit |
|
||||
| Remote resources | Denied by CSP and resource interception |
|
||||
|
||||
@@ -46,10 +46,21 @@ public sealed class AppSettings : ShellSettings
|
||||
public double OutlineWidth { get; set; } = 220;
|
||||
|
||||
|
||||
/// <summary>Shows the literal, read-only Markdown snapshot beside the rendered document.</summary>
|
||||
public bool ShowSource { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>Last source pane width in device-independent pixels.</summary>
|
||||
public double SourceWidth { get; set; } = 320;
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Sanitize()
|
||||
{
|
||||
base.Sanitize();
|
||||
SourceWidth = double.IsFinite(SourceWidth) ? Math.Clamp(SourceWidth, 160, 600) : 320;
|
||||
OutlineDepth = Math.Clamp(OutlineDepth, 1, 6);
|
||||
OutlineWidth = double.IsFinite(OutlineWidth) ? Math.Clamp(OutlineWidth, 140, 500) : 220;
|
||||
Frontmatter = FrontmatterKind.ToString();
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2026 James Maes
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
|
||||
|
||||
namespace MarkdownViewr.Windows;
|
||||
|
||||
/// <summary>Opt-in native event evidence for isolated fixtures; never records document text or keystrokes.</summary>
|
||||
public sealed partial class MainWindow
|
||||
{
|
||||
/// <summary>Observes handled events without changing routing, focus, capture or control behavior.</summary>
|
||||
private void InitializeInputDiagnostics()
|
||||
{
|
||||
if(!string.Equals(Environment.GetEnvironmentVariable("MARKDOWNVIEWR_INPUT_TRACE"), "1", StringComparison.Ordinal))
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach(UIElement element in new UIElement[] { RootGrid, OutlineDivider, SourceDivider, FrontmatterHide, FrontmatterMetadata, FrontmatterMarkdown })
|
||||
{
|
||||
element.AddHandler(UIElement.PointerPressedEvent, new PointerEventHandler((sender, args) => TracePointer("pressed", sender, args)), handledEventsToo: true);
|
||||
element.AddHandler(UIElement.PointerReleasedEvent, new PointerEventHandler((sender, args) => TracePointer("released", sender, args)), handledEventsToo: true);
|
||||
element.AddHandler(UIElement.PointerCaptureLostEvent, new PointerEventHandler((sender, args) => TracePointer("capture-lost", sender, args)), handledEventsToo: true);
|
||||
}
|
||||
OutlineDivider.DragStarted += (_, args) => App.Log.Info(FormattableString.Invariant($"Input trace: outline drag started; x={args.HorizontalOffset}; y={args.VerticalOffset}."));
|
||||
OutlineDivider.DragDelta += (_, args) => App.Log.Info(FormattableString.Invariant($"Input trace: outline drag delta; x={args.HorizontalChange}; y={args.VerticalChange}."));
|
||||
OutlineDivider.DragCompleted += (_, args) => App.Log.Info(FormattableString.Invariant($"Input trace: outline drag completed; canceled={args.Canceled}."));
|
||||
foreach(Microsoft.UI.Xaml.Controls.RadioMenuFlyoutItem item in new[] { FrontmatterHide, FrontmatterMetadata, FrontmatterMarkdown })
|
||||
{
|
||||
item.Click += (_, _) => App.Log.Info($"Input trace: {item.Name} click; checked={item.IsChecked}.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>Records only owned native control names, button state and local pointer coordinates.</summary>
|
||||
private void TracePointer(string operation, object sender, PointerRoutedEventArgs args)
|
||||
{
|
||||
Microsoft.UI.Input.PointerPoint point = args.GetCurrentPoint((UIElement)sender);
|
||||
App.Log.Info(FormattableString.Invariant($"Input trace: {operation}; target={((FrameworkElement)sender).Name}; source={(args.OriginalSource as FrameworkElement)?.Name}; left={point.Properties.IsLeftButtonPressed}; handled={args.Handled}; x={point.Position.X}; y={point.Position.Y}."));
|
||||
}
|
||||
}
|
||||
@@ -34,8 +34,7 @@ public sealed partial class MainWindow
|
||||
private void ApplyOutlineVisibility()
|
||||
{
|
||||
OutlinePanel.Visibility = _settings.ShowOutline ? Visibility.Visible : Visibility.Collapsed;
|
||||
OutlineColumn.Width = new GridLength(_settings.ShowOutline ? _settings.OutlineWidth : 0);
|
||||
OutlineDividerColumn.Width = new GridLength(_settings.ShowOutline ? 6 : 0);
|
||||
ApplyReadingWidths();
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +128,7 @@ public sealed partial class MainWindow
|
||||
private void OutlineDivider_DragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
_settings.OutlineWidth = Math.Clamp(OutlineColumn.ActualWidth + e.HorizontalChange, 140, 500);
|
||||
OutlineColumn.Width = new GridLength(_settings.OutlineWidth);
|
||||
ApplyReadingWidths();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2026 James Maes
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
|
||||
|
||||
namespace MarkdownViewr.Windows;
|
||||
|
||||
/// <summary>Displays the same committed snapshot as literal text, without passing source through HTML.</summary>
|
||||
public sealed partial class MainWindow
|
||||
{
|
||||
private string _sourceMarkdown = "";
|
||||
|
||||
|
||||
|
||||
/// <summary>Restores the independent source preference after XAML initialization.</summary>
|
||||
private void InitializeSource()
|
||||
{
|
||||
SourceToggle.IsChecked = _settings.ShowSource;
|
||||
RefreshSource();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>A hidden source pane relinquishes its columns and accessibility surface.</summary>
|
||||
private void RefreshSource()
|
||||
{
|
||||
ApplyReadingWidths();
|
||||
SourceText.Visibility = _settings.ShowSource ? Visibility.Visible : Visibility.Collapsed;
|
||||
string text = _settings.ShowSource ? _sourceMarkdown : "";
|
||||
if(!string.Equals(SourceText.Text, text, StringComparison.Ordinal))
|
||||
{
|
||||
SourceText.Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>Constrains displayed pane widths while retaining the user's preferred widths for larger windows.</summary>
|
||||
private void ApplyReadingWidths()
|
||||
{
|
||||
double available = Math.Max(0, RootGrid.ActualWidth - 200);
|
||||
double outline = _settings.ShowOutline ? Math.Min(_settings.OutlineWidth, Math.Max(0, available - 6 - (_settings.ShowSource ? 166 : 0))) : 0;
|
||||
double source = _settings.ShowSource ? Math.Min(_settings.SourceWidth, Math.Max(0, available - outline - (_settings.ShowOutline ? 6 : 0) - 6)) : 0;
|
||||
OutlineColumn.Width = new GridLength(outline);
|
||||
OutlineDividerColumn.Width = new GridLength(_settings.ShowOutline ? 6 : 0);
|
||||
SourceColumn.Width = new GridLength(source);
|
||||
SourceDividerColumn.Width = new GridLength(_settings.ShowSource ? 6 : 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>Keeps at least 200 reading pixels when the window shrinks or both panes are open.</summary>
|
||||
private void ReadingArea_SizeChanged(object sender, SizeChangedEventArgs e) => ApplyReadingWidths();
|
||||
|
||||
|
||||
/// <summary>Persists the view choice while preserving the actual Markdown, including hidden frontmatter.</summary>
|
||||
private void Source_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_settings.ShowSource = SourceToggle.IsChecked;
|
||||
Save();
|
||||
RefreshSource();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>The source pane grows toward the left and stays within its validated width range.</summary>
|
||||
private void SourceDivider_DragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
_settings.SourceWidth = Math.Clamp(SourceColumn.ActualWidth - e.HorizontalChange, 160, 600);
|
||||
ApplyReadingWidths();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>Writes the completed resize through AppKit's atomic settings store.</summary>
|
||||
private void SourceDivider_DragCompleted(object sender, DragCompletedEventArgs e) => Save();
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
<MicaBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
|
||||
<Grid x:Name="RootGrid">
|
||||
<Grid x:Name="RootGrid" SizeChanged="ReadingArea_SizeChanged">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@@ -28,6 +28,7 @@
|
||||
<MenuFlyoutItem x:Name="ExitMenuItem" Text="Exit" Click="Exit_Click" />
|
||||
</MenuBarItem>
|
||||
<MenuBarItem Title="View">
|
||||
<ToggleMenuFlyoutItem x:Name="SourceToggle" Text="Markdown source" Click="Source_Click" />
|
||||
<ToggleMenuFlyoutItem x:Name="OutlineToggle" Text="Table of contents" Click="Outline_Click" />
|
||||
<MenuFlyoutSeparator />
|
||||
<MenuFlyoutSubItem x:Name="DocumentThemesMenu" Text="Document theme" />
|
||||
@@ -61,6 +62,8 @@
|
||||
<ColumnDefinition x:Name="OutlineColumn" Width="0" />
|
||||
<ColumnDefinition x:Name="OutlineDividerColumn" Width="0" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition x:Name="SourceDividerColumn" Width="0" />
|
||||
<ColumnDefinition x:Name="SourceColumn" Width="0" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid x:Name="OutlinePanel" Visibility="Collapsed" Padding="8">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -94,6 +97,14 @@
|
||||
</primitives:Thumb.Template>
|
||||
</primitives:Thumb>
|
||||
<WebView2 x:Name="DocumentView" Grid.Column="2" Loaded="DocumentView_Loaded" AutomationProperties.Name="Markdown document" />
|
||||
<primitives:Thumb x:Name="SourceDivider" Grid.Column="3" Background="{ThemeResource DividerStrokeColorDefaultBrush}" DragDelta="SourceDivider_DragDelta" DragCompleted="SourceDivider_DragCompleted" AutomationProperties.Name="Resize Markdown source">
|
||||
<primitives:Thumb.Template>
|
||||
<ControlTemplate TargetType="primitives:Thumb">
|
||||
<Border Background="{TemplateBinding Background}" />
|
||||
</ControlTemplate>
|
||||
</primitives:Thumb.Template>
|
||||
</primitives:Thumb>
|
||||
<TextBox x:Name="SourceText" Grid.Column="4" Visibility="Collapsed" IsReadOnly="True" AcceptsReturn="True" TextWrapping="NoWrap" FontFamily="Consolas" Padding="12" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" AutomationProperties.Name="Markdown source" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -40,6 +40,8 @@ public sealed partial class MainWindow : Window, IDisposable
|
||||
_browser = new DocumentBrowser(DocumentView, message => StatusText.Text = message, ActiveDocumentTheme());
|
||||
CreateDocumentThemeMenu();
|
||||
InitializeOutline();
|
||||
InitializeSource();
|
||||
InitializeInputDiagnostics();
|
||||
(_settings.FrontmatterKind switch { Core.Documents.FrontmatterMode.Metadata => FrontmatterMetadata, Core.Documents.FrontmatterMode.Markdown => FrontmatterMarkdown, _ => FrontmatterHide }).IsChecked = true;
|
||||
Title = AppIdentity.Info.DisplayName;
|
||||
FitInitialWindow();
|
||||
@@ -280,6 +282,8 @@ public sealed partial class MainWindow : Window, IDisposable
|
||||
private void ShowDocument(DocumentFiles files, Core.Documents.DocumentOutline outline, string path, Core.Documents.DocumentViewport viewport, bool reload)
|
||||
{
|
||||
_browser.Show(files, outline.Html, Path.GetFileName(path), viewport, outline.Headings);
|
||||
_sourceMarkdown = files.Markdown;
|
||||
RefreshSource();
|
||||
_outline = outline;
|
||||
RefreshOutline();
|
||||
_documentPath = Path.GetFullPath(path);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2026 James Maes
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
|
||||
namespace MarkdownViewr.Windows.Core.Tests;
|
||||
|
||||
/// <summary>Invalid saved widths cannot hide the reading surface or prevent startup.</summary>
|
||||
public sealed class SourcePreferencesTests
|
||||
{
|
||||
/// <summary>Both visibility choices retain bounded widths; nonfinite values restore the default.</summary>
|
||||
[Theory]
|
||||
[InlineData(true, double.NaN, 320)]
|
||||
[InlineData(false, double.PositiveInfinity, 320)]
|
||||
[InlineData(true, -100, 160)]
|
||||
[InlineData(false, 900, 600)]
|
||||
[InlineData(true, 280, 280)]
|
||||
public void Sanitize_SourcePreferences_RetainsVisibilityAndClampsWidth(bool visible, double width, double expected)
|
||||
{
|
||||
var settings = new AppSettings { ShowSource = visible, SourceWidth = width };
|
||||
settings.Sanitize();
|
||||
Assert.Equal(visible, settings.ShowSource);
|
||||
Assert.Equal(expected, settings.SourceWidth);
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ public sealed class AppSession : IDisposable
|
||||
|
||||
var startInfo = new ProcessStartInfo(ExePath) { WorkingDirectory = Path.GetDirectoryName(ExePath) ?? "" };
|
||||
startInfo.Environment[AppIdentity.Info.DataDirectoryVariable] = DataDirectory;
|
||||
startInfo.Environment["MARKDOWNVIEWR_INPUT_TRACE"] = "1";
|
||||
if(document is not null)
|
||||
{
|
||||
string path = Path.Combine(DataDirectory, "document.md");
|
||||
|
||||
@@ -206,6 +206,35 @@ public class AppTests
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Source remains literal and read-only, follows committed reloads and persists its visibility.</summary>
|
||||
[Fact]
|
||||
public void Source_ShowReloadAndHide_PreservesLiteralSnapshot()
|
||||
{
|
||||
const string Markdown = "---\nsecret: literal metadata\n---\n# Source acceptance\n\n<script>document.body.textContent='Executed source';</script>\n\n```html\n<button onclick='evil()'>Literal code</button>\n```";
|
||||
using var session = new AppSession(document: Markdown);
|
||||
session.WaitFor(() => session.FindInApp(cf => cf.ByName("Source acceptance")), "the document heading", TimeSpan.FromSeconds(30));
|
||||
Assert.Null(session.FindInApp(cf => cf.ByAutomationId("SourceText")));
|
||||
session.InvokeMenuItem("View", "SourceToggle");
|
||||
AutomationElement source = session.WaitForElement("SourceText");
|
||||
Assert.True(source.Patterns.Value.Pattern.IsReadOnly.Value);
|
||||
string value = source.Patterns.Value.Pattern.Value.Value.Replace("\r\n", "\n", StringComparison.Ordinal);
|
||||
Assert.Equal(Markdown, value);
|
||||
using(var settings = JsonDocument.Parse(session.ReadSettings()))
|
||||
{
|
||||
Assert.True(settings.RootElement.GetProperty("ShowSource").GetBoolean());
|
||||
Assert.Equal(320, settings.RootElement.GetProperty("SourceWidth").GetDouble());
|
||||
}
|
||||
File.WriteAllText(Path.Combine(session.DataDirectory, "document.md"), "# Source replacement\n\n**New literal text**");
|
||||
session.WaitFor(() => source.Patterns.Value.Pattern.Value.Value.Contains("**New literal text**", StringComparison.Ordinal) ? source : null, "the source snapshot after reload");
|
||||
session.WaitFor(() => session.FindInApp(cf => cf.ByName("Source replacement")), "the rendered replacement heading");
|
||||
session.InvokeMenuItem("View", "SourceToggle");
|
||||
session.WaitForElementGone("SourceText");
|
||||
using var hidden = JsonDocument.Parse(session.ReadSettings());
|
||||
Assert.False(hidden.RootElement.GetProperty("ShowSource").GetBoolean());
|
||||
_output.WriteLine(session.DescribeDocumentStatus());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>The native depth choice filters exact headings and a real divider drag saves its new width.</summary>
|
||||
[Fact]
|
||||
public void Outline_DepthAndResize_PersistsNativeChoices()
|
||||
@@ -245,7 +274,7 @@ public class AppTests
|
||||
}
|
||||
catch(TimeoutException exception)
|
||||
{
|
||||
throw new TimeoutException($"{exception.Message} Divider: {divider.BoundingRectangle}; pointer: {FlaUI.Core.Input.Mouse.Position}; settings: {session.ReadSettings()}; tree: {session.DescribeDocumentStatus()}", exception);
|
||||
throw new TimeoutException($"{exception.Message} Divider: {divider.BoundingRectangle}; pointer: {FlaUI.Core.Input.Mouse.Position}; logs: {session.ReadLogs()}; settings: {session.ReadSettings()}; tree: {session.DescribeDocumentStatus()}", exception);
|
||||
}
|
||||
using var saved = JsonDocument.Parse(session.ReadSettings());
|
||||
Assert.True(saved.RootElement.GetProperty("ShowOutline").GetBoolean());
|
||||
|
||||
Reference in new issue
Block a user