Context
#57 establishes real-provider/core E2E for SyncManager + production GitHub/GitLab/Gitea services. That layer should remain headless and deterministic.
This issue adds a second E2E layer for the actual Obsidian desktop experience: launch Obsidian, load the built plugin into an isolated vault, operate the plugin through its real GUI, and verify remote state against a real provider using an independent raw API verifier.
Goal
Verify that a user can complete the critical sync workflow through the real Obsidian GUI, not only through service classes.
The GUI suite must prove both sides of the boundary:
Playwright
-> real Obsidian Desktop
-> plugin UI / commands / settings
-> SyncManager
-> production provider service
-> real Git provider
-> independent raw API verification
A success toast alone is never sufficient evidence of a successful remote operation.
Dependency
Scope v1
Desktop harness
GUI smoke contract — all providers
Run the same minimal user workflow against GitHub, GitLab, and Gitea:
Canonical GUI provider — GitHub
Use GitHub as the exhaustive GUI provider after the cross-provider smoke contract is stable:
Do not multiply every exhaustive GUI case across all three providers unless a case is genuinely provider-specific.
Provider matrix
| Layer |
GitHub |
GitLab |
Gitea |
| Provider/core contract (#57) |
Full |
Full |
Full |
| SyncManager real-provider (#57) |
Full |
Full |
Full |
| GUI smoke |
Full |
Basic |
Basic |
| GUI exhaustive |
Canonical |
No |
No |
Provider-specific API semantics continue to belong in #57. GUI tests are responsible for user-visible wiring and Obsidian integration.
High-value regressions this layer should catch
- settings page fails to render on a supported Obsidian version;
- provider selector/settings are not propagated into the production service;
- command/ribbon/context-menu registration breaks;
- modal or confirmation wiring blocks an operation;
- Vault create/rename/delete event ordering causes an incorrect sync action;
- plugin reload loses persisted configuration or sync metadata;
- UI reports success although the remote repository was not changed;
- remote update succeeds but the Obsidian editor/Vault is not refreshed;
- Obsidian API changes break plugin initialization while unit/core E2E remain green.
Test architecture
Suggested structure:
e2e-gui/
├── playwright.config.ts
├── fixtures/
│ ├── obsidian-app.ts
│ ├── test-vault.ts
│ └── plugin-build.ts
├── pages/
│ ├── settings-page.ts
│ └── sync-ui.ts
├── suites/
│ ├── provider-smoke.spec.ts
│ └── github-full.spec.ts
└── helpers/
└── diagnostics.ts
Prefer semantic selectors (getByRole, accessible name, stable data-* hooks where needed) over brittle CSS/layout selectors.
Credentials and sandboxing
CI strategy
Phase-in after local/manual stability:
- local GUI E2E against GitHub;
- manual
workflow_dispatch for all providers;
- GitHub GUI smoke on internal PRs touching UI/sync/provider integration;
- GitLab/Gitea GUI smoke on main/manual/scheduled runs as stability permits.
Do not make the entire three-provider GUI matrix a required PR check initially. Keep #57's headless/core suite as the deterministic release gate; promote GUI checks only after flake rate is acceptable.
Acceptance criteria
Non-goals
Context
#57 establishes real-provider/core E2E for
SyncManager+ production GitHub/GitLab/Gitea services. That layer should remain headless and deterministic.This issue adds a second E2E layer for the actual Obsidian desktop experience: launch Obsidian, load the built plugin into an isolated vault, operate the plugin through its real GUI, and verify remote state against a real provider using an independent raw API verifier.
Goal
Verify that a user can complete the critical sync workflow through the real Obsidian GUI, not only through service classes.
The GUI suite must prove both sides of the boundary:
A success toast alone is never sufficient evidence of a successful remote operation.
Dependency
Scope v1
Desktop harness
main.js,manifest.json,styles.css) into the test vault.GUI smoke contract — all providers
Run the same minimal user workflow against GitHub, GitLab, and Gitea:
Canonical GUI provider — GitHub
Use GitHub as the exhaustive GUI provider after the cross-provider smoke contract is stable:
Do not multiply every exhaustive GUI case across all three providers unless a case is genuinely provider-specific.
Provider matrix
Provider-specific API semantics continue to belong in #57. GUI tests are responsible for user-visible wiring and Obsidian integration.
High-value regressions this layer should catch
Test architecture
Suggested structure:
Prefer semantic selectors (
getByRole, accessible name, stabledata-*hooks where needed) over brittle CSS/layout selectors.Credentials and sandboxing
CI strategy
Phase-in after local/manual stability:
workflow_dispatchfor all providers;Do not make the entire three-provider GUI matrix a required PR check initially. Keep #57's headless/core suite as the deterministic release gate; promote GUI checks only after flake rate is acceptable.
Acceptance criteria
settings -> connection -> push -> remote verify -> remote mutate -> pull -> local verify.Non-goals