/* eslint-disable @typescript-eslint/no-deprecated -- exercising the Obsidian < 1.13 display() compat fallback intentionally */ import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { App } from 'obsidian'; import { DEFAULT_SETTINGS, GitLabSyncSettingTab } from '../../src/settings'; import GitLabFilesPush from '../../src/main'; import { createContainer, setupObsidianDOM } from './setup-dom'; vi.mock('../../src/main', () => ({ default: class {}, })); beforeAll(() => { setupObsidianDOM(); }); function createPluginStub(testConnection: ReturnType): GitLabFilesPush { return { settings: { ...DEFAULT_SETTINGS }, saveSettings: vi.fn().mockResolvedValue(undefined), initializeGitService: vi.fn(), gitService: { testConnection }, } as unknown as GitLabFilesPush; } function scheduleConnectionTest(tab: GitLabSyncSettingTab): void { (tab as unknown as { scheduleConnectionTest: () => void }).scheduleConnectionTest(); } describe('GitLabSyncSettingTab connection status badge', () => { beforeEach(() => { vi.useFakeTimers(); }); it('shows checking then connected after opening the tab', async () => { const testConnection = vi.fn().mockResolvedValue({ repoOk: true, branchOk: true }); const tab = new GitLabSyncSettingTab(new App(), createPluginStub(testConnection)); tab.containerEl = createContainer(); tab.display(); const badge = tab.containerEl.querySelector('.gfs-connection-status') as HTMLElement; expect(badge.classList.contains('is-checking')).toBe(true); await vi.advanceTimersByTimeAsync(800); expect(testConnection).toHaveBeenCalledTimes(1); expect(badge.classList.contains('is-connected')).toBe(true); expect(badge.textContent).toBe('Connected'); vi.useRealTimers(); }); it('debounces repeated field edits into a single connection test', async () => { const testConnection = vi.fn().mockResolvedValue({ repoOk: false, branchOk: false, error: 'bad token' }); const plugin = createPluginStub(testConnection); const tab = new GitLabSyncSettingTab(new App(), plugin); tab.containerEl = createContainer(); tab.display(); await vi.advanceTimersByTimeAsync(800); testConnection.mockClear(); // Simulate rapid keystrokes in the token field via the debounced hook directly. scheduleConnectionTest(tab); scheduleConnectionTest(tab); scheduleConnectionTest(tab); await vi.advanceTimersByTimeAsync(799); expect(testConnection).not.toHaveBeenCalled(); await vi.advanceTimersByTimeAsync(1); expect(testConnection).toHaveBeenCalledTimes(1); const badge = tab.containerEl.querySelector('.gfs-connection-status') as HTMLElement; expect(badge.classList.contains('is-disconnected')).toBe(true); expect(badge.textContent).toContain('bad token'); vi.useRealTimers(); }); }); describe('GitLabSyncSettingTab ignore patterns setting', () => { it('renders a textarea seeded with the saved ignorePatterns value', async () => { const plugin = createPluginStub(vi.fn().mockResolvedValue({ repoOk: true, branchOk: true })); plugin.settings.ignorePatterns = 'draft/\n*.tmp'; const tab = new GitLabSyncSettingTab(new App(), plugin); tab.containerEl = createContainer(); vi.useFakeTimers(); tab.display(); await vi.advanceTimersByTimeAsync(800); vi.useRealTimers(); const textarea = tab.containerEl.querySelector('textarea') as HTMLTextAreaElement; expect(textarea.value).toBe('draft/\n*.tmp'); }); });