feat: git badge for waiting commits

This commit is contained in:
2026-02-21 18:58:00 +01:00
parent c192237185
commit 73a8b6803f
4 changed files with 220 additions and 4 deletions

View File

@@ -1,13 +1,47 @@
import React from 'react';
import { beforeEach, describe, expect, it } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { act, fireEvent, render, screen } from '@testing-library/react';
import { ActivityBar } from '../../../src/renderer/components/ActivityBar/ActivityBar';
import { I18nProvider } from '../../../src/renderer/i18n';
import { useAppStore } from '../../../src/renderer/store';
describe('ActivityBar tags behavior', () => {
beforeEach(() => {
(window as any).electronAPI = {
...(window as any).electronAPI,
app: {
...(window as any).electronAPI?.app,
getDefaultProjectPath: vi.fn().mockResolvedValue('/repo/path'),
},
git: {
...(window as any).electronAPI?.git,
getRepoState: vi.fn().mockResolvedValue({
isRepo: true,
rootPath: '/repo/path',
currentBranch: 'main',
hasRemote: true,
}),
fetch: vi.fn().mockResolvedValue({ success: true }),
getRemoteState: vi.fn().mockResolvedValue({
localBranch: 'main',
upstreamBranch: 'origin/main',
hasUpstream: true,
ahead: 0,
behind: 0,
}),
},
};
useAppStore.setState({
activeProject: {
id: 'project-1',
name: 'Test Project',
slug: 'test-project',
dataPath: '/repo/path',
isActive: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
activeView: 'posts',
sidebarVisible: true,
tabs: [],
@@ -15,6 +49,10 @@ describe('ActivityBar tags behavior', () => {
});
});
afterEach(() => {
vi.useRealTimers();
});
it('switches sidebar to tags view when clicking Tags', () => {
render(
<I18nProvider>
@@ -95,4 +133,69 @@ describe('ActivityBar tags behavior', () => {
expect(screen.getByTitle('Tags (click again to toggle sidebar)')).toBeInTheDocument();
});
it('shows a badge on the git activity icon when remote commits are available to pull', async () => {
(window as any).electronAPI.git.getRemoteState = vi.fn().mockResolvedValue({
localBranch: 'main',
upstreamBranch: 'origin/main',
hasUpstream: true,
ahead: 0,
behind: 4,
});
render(
<I18nProvider>
<ActivityBar />
</I18nProvider>
);
expect(await screen.findByText('4')).toHaveClass('activity-bar-badge');
});
it('polls remote git status on a regular interval', async () => {
vi.useFakeTimers();
render(
<I18nProvider>
<ActivityBar />
</I18nProvider>
);
await vi.waitFor(() => {
expect((window as any).electronAPI.git.fetch).toHaveBeenCalledTimes(1);
expect((window as any).electronAPI.git.getRemoteState).toHaveBeenCalledTimes(1);
});
await act(async () => {
vi.advanceTimersByTime(30000);
});
await vi.waitFor(() => {
expect((window as any).electronAPI.git.fetch).toHaveBeenCalledTimes(2);
expect((window as any).electronAPI.git.getRemoteState).toHaveBeenCalledTimes(2);
});
});
it('skips periodic git fetch polling while offline', async () => {
vi.useFakeTimers();
Object.defineProperty(globalThis.navigator, 'onLine', {
configurable: true,
value: false,
});
render(
<I18nProvider>
<ActivityBar />
</I18nProvider>
);
await act(async () => {
vi.advanceTimersByTime(60000);
await Promise.resolve();
await Promise.resolve();
});
expect((window as any).electronAPI.git.fetch).toHaveBeenCalledTimes(0);
expect((window as any).electronAPI.git.getRemoteState).toHaveBeenCalledTimes(0);
});
});