Skip to content

Expand assembled-desktop E2E coverage across critical native boundaries #181

Description

@Azganoth

Summary

Expand Leafdown’s Windows-local assembled-desktop E2E suite from its initial diagnostics smoke test with five focused scenarios covering the highest-value gaps between the existing frontend and backend test layers:

  1. Document open, edit, save, and reopen.
  2. Folder context, article navigation, and real watcher refresh.
  3. Real backend error propagation into visible frontend feedback.
  4. Persisted settings across an application restart.
  5. Injected titlebar controls and clean window shutdown.

Implement the five scenarios in one branch and pull request. Retain the current frontend, Rust, and assembled-desktop diagnostics tests: the new E2E scenarios should sample behavior unique to the assembled application rather than reproduce existing algorithmic and edge-case matrices.

This issue absorbs the Project drafts “Desktop E2E coverage for the document lifecycle” and “Desktop E2E coverage for folder context and watcher refresh.”

Affected areas

  • e2e/desktop/specs/
  • e2e/desktop/support/
  • E2E fixture setup and cleanup
  • Isolated E2E preferences and recent-item state
  • WebdriverIO application restart and shutdown orchestration
  • Document and folder workflows as exercised through the rendered application
  • Application command state and keyboard shortcut routing
  • Folder watcher delivery and refresh diagnostics
  • Window-control injection and close lifecycle
  • Local ignored E2E artifacts

Production behavior, ordinary Tauri configuration, and the existing automated test layers should remain unchanged unless a separately justified correction is discovered.

Intended outcome

pnpm test:e2e:desktop retains the existing Help → Diagnostics smoke test and adds five independently diagnosable assembled-desktop scenarios against the real Leafdown test-feature binary with one worker.

Each scenario must:

  • use stable semantic selectors;
  • cross a genuine native boundary through Leafdown’s real APIs;
  • use run-owned temporary files or isolated E2E application data;
  • avoid personal files and ordinary Leafdown state;
  • avoid native file-picker and confirmation-dialog automation;
  • use bounded condition-based waits rather than fixed sleeps;
  • retain actionable local failure evidence;
  • clean up its temporary fixtures;
  • leave no Leafdown or driver processes or listening E2E port after completion.

Use rendered interaction for acceptance behavior. Reserve browser.tauri.execute() for bounded setup, corroboration, or diagnostics; it must not substitute for the UI path being asserted.

Document lifecycle and command propagation

Use a temporary copy of a small committed Markdown fixture and seed it into the isolated recent-file store before launch.

Through the rendered application:

  1. Open the fixture from File → Open recent.
  2. Verify the initial fixture marker is displayed.
  3. Verify Save is disabled while the document is clean.
  4. Edit the document through the real Milkdown WebView.
  5. Verify Save becomes enabled.
  6. Save with Ctrl+S.
  7. Verify Save becomes disabled again.
  8. Assert the temporary file contains the exact expected bytes.
  9. Close and reopen the document through Open recent.
  10. Assert the saved fixture marker is displayed.

This scenario should distinguish failures in UI interaction, editor serialization, command-state propagation, shortcut routing, IPC, filesystem persistence, and reopen behavior.

Folder context and watcher refresh

Use a controlled temporary folder fixture containing a root document and one existing article. Seed the folder into the isolated recent-folder store.

Through the rendered application:

  1. Open the folder from File → Open recent.
  2. Verify the existing article appears in the navigator.
  3. Wait for structured evidence that the native watcher started.
  4. Create one new Markdown file externally through the test runner.
  5. Wait for the new semantic article row.
  6. Open the new article and verify its fixture marker.

Cover one successful real filesystem-event chain only. Rename, deletion, ignored-directory, event-burst, stale-scope, and watcher-error matrices remain owned by the existing frontend and Rust tests.

Backend error propagation

Seed a recent-file entry pointing to a guaranteed-absent Markdown path inside the run-owned temporary directory.

Through File → Open recent:

  1. Attempt to open the missing file.
  2. Verify the visible “Markdown file not found” feedback.
  3. Verify the message identifies the expected fixture path.
  4. Retain correlated frontend and backend evidence identifying the missingFile error kind and document-open operation.

The acceptance assertion must use the rendered error feedback rather than invoking the command directly.

Persistence across restart

From a controlled baseline settings file:

  1. Change one low-risk visible setting through the UI, preferably sidebar visibility.
  2. Verify its immediate menu and rendered state.
  3. Restart the WebDriver-managed Leafdown process.
  4. Verify a new application run ID.
  5. Verify the setting is restored through the rendered UI.
  6. Verify the isolated persisted settings file contains the expected sanitized state.

The restart must be owned by the runner and must not depend on state from an earlier manual E2E run.

Titlebar and clean shutdown

Run this scenario last in its own application session.

  1. Verify the real tauri-plugin-frame controls expose the expected accessible names.
  2. Verify the injected controls have tabindex="-1".
  3. Activate the real Close window control from a clean welcome state.
  4. Verify the frontend records its window-closing lifecycle diagnostic.
  5. Verify the application process exits within a bounded deadline.
  6. Verify no Leafdown or driver process and no E2E port listener remain.

Dirty-document confirmation is not part of this scenario.

Related context

Done when

Shared harness behavior

  • The existing Help → Diagnostics real-IPC smoke test remains and continues to pass; the five scenarios in this issue are additive.
  • All five new scenarios run through pnpm test:e2e:desktop with one worker.
  • Each scenario runs in a fresh deterministic application session or performs an equivalent verified state reset.
  • The persistence scenario intentionally spans two launches of the same isolated E2E state.
  • The clean-shutdown scenario runs in its own final session so the expected WebDriver disconnection cannot affect another scenario.
  • Every scenario starts from deterministic E2E preferences, recent items, and temporary filesystem state.
  • Fixture setup and cleanup never access or modify ordinary Leafdown application data.
  • Acceptance behavior is driven through semantic UI interaction.
  • Direct Tauri execution is limited to setup, corroboration, or diagnostics.
  • Condition-based waits have explicit deadlines; no fixed sleeps are used for application or watcher readiness.
  • Failures retain the existing screenshot, semantic state, test error, diagnostics summary, and correlated frontend/backend logs.
  • Fixture-backed failures also retain a safe manifest containing fixture paths, expected and actual file lengths or hashes, and relevant timestamps.
  • Diagnostic artifacts do not intentionally capture arbitrary editor content.
  • Passing and failing runs leave no Leafdown or driver processes and no listener on the E2E port.

Scenario acceptance

  • A temporary Markdown fixture opens through Open recent using real IPC.
  • Editing changes the rendered Save state from disabled to enabled.
  • Ctrl+S writes the exact expected fixture bytes and returns Save to disabled.
  • Closing and reopening displays the saved fixture marker.
  • A temporary folder opens through Open recent and displays its existing article.
  • An external Markdown-file creation is delivered through the real watcher and appears in the navigator.
  • The watcher-added article opens and displays its fixture marker.
  • A real missing-file command failure crosses IPC and produces the expected visible message.
  • One setting changed through the UI survives a genuine application restart.
  • Real injected titlebar controls retain their accessible names and remain outside the tab sequence.
  • Activating Close window completes the real backend/frontend close lifecycle and terminates the process.

Existing coverage and verification

  • Existing frontend, Rust, and assembled-desktop diagnostics tests remain in their current layers; none are replaced solely because additional E2E coverage exists.
  • pnpm check passes.
  • pnpm test:e2e:desktop passes from a deterministic baseline.
  • A representative forced failure retains the expected diagnostic evidence and exits nonzero.
  • Ordinary development and production builds remain free of WDIO plugins, permissions, bridge code, and E2E identifiers.
  • Documentation is updated only if commands, prerequisites, artifact behavior, or durable verification guidance change.
  • No changelog entry is added unless shipped user behavior changes.

Notes

Implementation direction

Keep each scenario independently identifiable in reporter output and artifacts even though all five ship in one branch and pull request.

A practical fixture strategy is:

  • commit only small, non-sensitive source fixtures;
  • copy them into a unique temporary root for each run;
  • pre-seed the E2E identifier’s persisted recent-item or settings files before application startup;
  • record the temporary root in the run’s artifact manifest;
  • clean temporary files and restore the deterministic application-data baseline during teardown.

The document-lifecycle scenario should carry the narrow Save menu and shortcut assertions because those assertions become valuable only when joined to a real editor edit and filesystem save.

Wait for explicit watcher-start evidence before applying the external filesystem change. Poll for the resulting semantic navigator state within a bounded deadline rather than sleeping for the frontend debounce interval.

Treat intentional application restart and shutdown as runner-owned lifecycle operations. The clean-close scenario should be last so the expected WebDriver disconnection cannot obscure another scenario.

If implementation requires shipped production hooks, broader WDIO permissions, weaker production capabilities, or a parallel application architecture, stop and revisit the scope before proceeding.

Expected flakiness

  • Document lifecycle: medium risk from editor focus and asynchronous save completion.
  • Folder watcher: medium-high risk from Windows notification batching and delivery delay.
  • Error propagation: low-medium risk from toast timing.
  • Persistence restart: medium risk from runner-controlled process relaunch.
  • Clean shutdown: medium-high risk from intentional WebDriver session termination and known service teardown warnings.

Mitigate these risks through semantic readiness, structured diagnostics, filesystem polling, process observation, and bounded deadlines—not retries that conceal nondeterminism.

Out of scope

  • Replacing existing frontend, Rust, or diagnostics smoke tests with the new scenarios
  • Native file-picker or confirmation-dialog automation
  • Dirty-document close, missing-file Save As, and external-modification confirmation workflows
  • Watcher rename, deletion, ignored-directory, burst, race, and error matrices
  • Broad menu or editor-shortcut duplication
  • Zoom, fullscreen, theme-change, and window-geometry coverage
  • Local image, local link, external opener, or operating-system application automation
  • Visual regression testing
  • Parallel E2E workers
  • Linux or macOS support
  • CI execution or artifact-retention policy
  • Production behavior changes made solely to accommodate the test harness

Metadata

Metadata

Assignees

Labels

MaintenanceChore, refactor, dependency, or test work without user-facing change

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions