Skip to content
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
53 changes: 53 additions & 0 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: E2E Tests

on:
push:
branches: [main, feature/*]
pull_request:
branches: [main]

jobs:
e2e:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build plugin
run: npm run build

# wdio-obsidian-service automatically downloads Obsidian
# but we need a display for the Electron app and 7z for extraction
- name: Setup virtual display and dependencies
run: |
sudo apt-get update
sudo apt-get install -y xvfb p7zip-full
Xvfb :99 -screen 0 1920x1080x24 &
echo "DISPLAY=:99" >> $GITHUB_ENV

- name: Run E2E tests
# Skip @slow tests in CI (they require real LLM API credentials)
# Run locally with: npm run wdio (full suite) or npm run wdio -- --mochaOpts.grep "@slow" (slow only)
run: npm run wdio -- --mochaOpts.grep "^(?!.*@slow).*$"
env:
DISPLAY: ':99'

- name: Upload test artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-artifacts
path: |
.wdio-obsidian/
test/vault/.obsidian/
retention-days: 7
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,15 @@ data.json

# Deliberate workflow
.deliberate/

# E2E test artifacts
test/vault/.obsidian/workspace.json
test/vault/.obsidian/workspace-mobile.json
test/vault/.obsidian/plugins/
test/vault/.obsidian/core-plugins.json
test/vault/.obsidian/community-plugins.json
test/vault/.obsidian/hotkeys.json
test/vault/.obsidian/appearance.json
test/vault/.trash/
.wdio-obsidian/
.obsidian-cache/
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ npm run dev
npm run build
```

### Testing in Obsidian
### Manual Testing in Obsidian

1. Create a test vault or use an existing one
2. Create a symbolic link from the build output to your vault's plugins folder:
Expand All @@ -124,6 +124,27 @@ npm run build
4. In Obsidian, enable the plugin and use Cmd/Ctrl+R to reload after changes
5. Open the Developer Console (Cmd/Ctrl+Shift+I) to see logs and errors

### E2E Testing

The plugin uses [wdio-obsidian-service](https://github.com/jesse-r-s-hines/wdio-obsidian-service) for end-to-end testing against a real Obsidian instance.

```bash
# Run E2E tests (builds first, then launches Obsidian)
npm run test:e2e

# Run E2E tests only (assumes already built)
npm run wdio
```

The test suite:
- Verifies plugin loads correctly
- Tests chat panel UI elements
- Tests user interaction (typing, sending messages)
- Tests settings navigation
- Tests context toggle functionality

Tests run automatically on GitHub Actions for pushes and pull requests.

## Architecture Notes

### Session Continuation
Expand Down
49 changes: 46 additions & 3 deletions main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,14 @@ export default class LLMPlugin extends Plugin {
}

/**
* Update the status bar with current provider info
* Update the status bar with current provider and model info
* @param provider Optional provider to display (uses default if not specified)
*/
updateStatusBar(provider?: LLMProvider) {
if (!this.statusBarEl) return;

const displayProvider = provider ?? this.settings.defaultProvider;
const providerConfig = this.settings.providers[displayProvider];
const providerNames: Record<string, string> = {
claude: "Claude",
opencode: "OpenCode",
Expand All @@ -271,13 +272,55 @@ export default class LLMPlugin extends Plugin {
};

this.statusBarEl.empty();
this.statusBarEl.addClass("llm-status-bar");

const indicator = this.statusBarEl.createSpan({ cls: "llm-status-indicator" });
this.statusBarEl.createSpan({ text: ` LLM: ${providerNames[displayProvider] || displayProvider}` });

// Build status text with provider and model
let statusText = providerNames[displayProvider] || displayProvider;
if (providerConfig?.model) {
// Show abbreviated model name
statusText += ` (${this.formatModelName(providerConfig.model)})`;
} else {
// Indicate CLI default is being used
statusText += " (default)";
}

this.statusBarEl.createSpan({
text: ` LLM: ${statusText}`,
cls: "llm-status-text",
});

// Check if provider is enabled
if (this.settings.providers[displayProvider]?.enabled) {
if (providerConfig?.enabled) {
indicator.addClass("active");
}
}

/**
* Format model name for display (abbreviate long names)
*/
private formatModelName(model: string): string {
// Common abbreviations
const abbreviations: Record<string, string> = {
"claude-3-5-haiku-latest": "haiku",
"claude-3-5-sonnet-latest": "sonnet-3.5",
"claude-sonnet-4-20250514": "sonnet-4",
"claude-opus-4-20250514": "opus-4",
"gemini-3.0-flash": "flash-3.0",
"gemini-2.0-flash-lite": "flash-lite",
"gemini-2.0-flash": "flash-2.0",
"gemini-2.5-flash": "flash-2.5",
"gemini-2.5-pro": "pro-2.5",
"gpt-4o-mini": "4o-mini",
"gpt-4o": "4o",
"gpt-5-nano": "5-nano",
"gpt-5-mini": "5-mini",
"gpt-5": "5",
"claude-sonnet": "sonnet",
"claude-haiku": "haiku",
};

return abbreviations[model] || model;
}
}
Loading