style: run prettier formatter over src and tests

This commit is contained in:
2026-06-11 20:46:00 +05:30
parent 2389d4f297
commit 6b564a4569
211 changed files with 6134 additions and 4234 deletions
+2 -4
View File
@@ -11,10 +11,8 @@ describe('Minimap', () => {
});
it('renders a viewport indicator', () => {
render(
<Minimap content={'line 1\nline 2\nline 3'} scrollRatio={0.5} visibleRatio={0.5} />
);
render(<Minimap content={'line 1\nline 2\nline 3'} scrollRatio={0.5} visibleRatio={0.5} />);
const indicator = screen.getByTestId('minimap-viewport');
expect(indicator).toBeInTheDocument();
});
});
});
+1 -1
View File
@@ -90,4 +90,4 @@ describe('AppHeader', () => {
await userEvent.click(screen.getByRole('button', { name: /^about$/i }));
expect(useAppStore.getState().modal).toEqual({ kind: 'about' });
});
});
});
+7 -2
View File
@@ -12,7 +12,12 @@ vi.mock('@/components/ui/resizable', () => ({
</div>
),
ResizablePanel: ({ children, defaultSize, minSize, maxSize }: any) => (
<div data-testid="resizable-panel" data-size={defaultSize} data-min={minSize} data-max={maxSize}>
<div
data-testid="resizable-panel"
data-size={defaultSize}
data-min={minSize}
data-max={maxSize}
>
{children}
</div>
),
@@ -46,4 +51,4 @@ describe('AppShell', () => {
);
expect(screen.queryByText(/file tree placeholder/i)).not.toBeInTheDocument();
});
});
});
+27 -5
View File
@@ -9,8 +9,15 @@ describe('Breadcrumb', () => {
beforeEach(() => {
localStorage.clear();
useSettingsStore.setState({ ...useSettingsStore.getInitialState(), breadcrumbSymbols: true });
useFileStore.setState({ activeTabId: '/test.md', openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }] } as any);
useEditorStore.setState({ buffers: new Map([['/test.md', { id: '/test.md', path: '/test.md', content: '# H1\n## H2', dirty: false }]]) } as any);
useFileStore.setState({
activeTabId: '/test.md',
openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }],
} as any);
useEditorStore.setState({
buffers: new Map([
['/test.md', { id: '/test.md', path: '/test.md', content: '# H1\n## H2', dirty: false }],
]),
} as any);
});
it('shows "No file selected" when no tab is active', () => {
@@ -38,8 +45,23 @@ describe('Breadcrumb', () => {
});
it('limits heading symbols to 3', () => {
useFileStore.setState({ activeTabId: '/test.md', openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }] } as any);
useEditorStore.setState({ buffers: new Map([['/test.md', { id: '/test.md', path: '/test.md', content: '# H1\n## H2\n### H3\n#### H4', dirty: false }]]) } as any);
useFileStore.setState({
activeTabId: '/test.md',
openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }],
} as any);
useEditorStore.setState({
buffers: new Map([
[
'/test.md',
{
id: '/test.md',
path: '/test.md',
content: '# H1\n## H2\n### H3\n#### H4',
dirty: false,
},
],
]),
} as any);
render(<Breadcrumb />);
// Should show H1, H2, H3 but not H4
expect(screen.getByText(/# H1/)).toBeInTheDocument();
@@ -47,4 +69,4 @@ describe('Breadcrumb', () => {
expect(screen.getByText(/# H3/)).toBeInTheDocument();
expect(screen.queryByText(/# H4/)).not.toBeInTheDocument();
});
});
});
+1 -1
View File
@@ -7,4 +7,4 @@ describe('StatusBar', () => {
render(<StatusBar />);
expect(screen.getByText(/0 words/i)).toBeInTheDocument();
});
});
});
+1 -3
View File
@@ -81,9 +81,7 @@ describe('TabBar', () => {
it('renders a dirty indicator when dirty === true', () => {
useFileStore.setState({
openTabs: [
{ id: '/tmp/foo.md', path: '/tmp/foo.md', title: 'foo.md', dirty: true },
],
openTabs: [{ id: '/tmp/foo.md', path: '/tmp/foo.md', title: 'foo.md', dirty: true }],
activeTabId: '/tmp/foo.md',
});
render(<TabBar />);
+1 -1
View File
@@ -31,4 +31,4 @@ describe('AboutDialog', () => {
// closeModal sets modal.kind = null, so isOpen=false, Dialog unmounts
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
});
});
@@ -32,4 +32,4 @@ describe('AsciiGeneratorDialog', () => {
render(<AsciiGeneratorDialog />);
expect(screen.getByRole('button', { name: /copy/i })).toBeInTheDocument();
});
});
});
@@ -34,10 +34,8 @@ describe('ConfirmDialog', () => {
});
it('destructive variant uses destructive button class', () => {
render(
<ConfirmDialog title="T" body="B" destructive onConfirm={() => {}} />
);
render(<ConfirmDialog title="T" body="B" destructive onConfirm={() => {}} />);
const btn = screen.getByRole('button', { name: /confirm/i });
expect(btn.className).toContain('bg-destructive');
});
});
});
@@ -18,7 +18,12 @@ describe('CrashReportModal', () => {
test('lists crashes returned by ipc', async () => {
(ipc.crash.read as any).mockResolvedValue([
{ filename: '1700000000000-1-uncaughtException.json', kind: 'uncaughtException', message: 'boom', timestamp: '2026-01-01T00:00:00.000Z' },
{
filename: '1700000000000-1-uncaughtException.json',
kind: 'uncaughtException',
message: 'boom',
timestamp: '2026-01-01T00:00:00.000Z',
},
]);
render(<CrashReportModal onClose={() => {}} />);
expect(await screen.findByText(/boom/)).toBeInTheDocument();
@@ -26,12 +31,19 @@ describe('CrashReportModal', () => {
test('delete button calls ipc.crash.delete', async () => {
(ipc.crash.read as any).mockResolvedValue([
{ filename: '1700000000000-1-uncaughtException.json', kind: 'uncaughtException', message: 'boom', timestamp: '2026-01-01T00:00:00.000Z' },
{
filename: '1700000000000-1-uncaughtException.json',
kind: 'uncaughtException',
message: 'boom',
timestamp: '2026-01-01T00:00:00.000Z',
},
]);
render(<CrashReportModal onClose={() => {}} />);
const btn = await screen.findByText(/delete/i);
fireEvent.click(btn);
await waitFor(() => expect(ipc.crash.delete).toHaveBeenCalledWith('1700000000000-1-uncaughtException.json'));
await waitFor(() =>
expect(ipc.crash.delete).toHaveBeenCalledWith('1700000000000-1-uncaughtException.json')
);
});
test('open folder button calls ipc.crash.openDir', async () => {
@@ -40,4 +52,4 @@ describe('CrashReportModal', () => {
fireEvent.click(await screen.findByText(/open dump folder/i));
expect(ipc.crash.openDir).toHaveBeenCalled();
});
});
});
@@ -7,7 +7,14 @@ describe('ExportBatchDialog', () => {
beforeEach(() => {
localStorage.clear();
window.electronAPI = {
export: { batch: vi.fn().mockResolvedValue({ ok: true, data: { total: 2, succeeded: 2, failed: 0, results: [] } }) },
export: {
batch: vi
.fn()
.mockResolvedValue({
ok: true,
data: { total: 2, succeeded: 2, failed: 0, results: [] },
}),
},
} as any;
});
@@ -23,7 +30,10 @@ describe('ExportBatchDialog', () => {
await userEvent.click(screen.getByRole('option', { name: /^pdf$/i }));
await userEvent.click(screen.getByRole('button', { name: /^export$/i }));
const call = (window.electronAPI.export.batch as any).mock.calls[0];
expect(call[0]).toEqual([{ inputPath: '/a.md', outputPath: expect.any(String) }, { inputPath: '/b.md', outputPath: expect.any(String) }]);
expect(call[0]).toEqual([
{ inputPath: '/a.md', outputPath: expect.any(String) },
{ inputPath: '/b.md', outputPath: expect.any(String) },
]);
expect(call[1].format).toBe('pdf');
});
});
@@ -14,7 +14,13 @@ vi.mock('@/lib/ipc', () => ({
}));
vi.mock('@/lib/docx-export', () => ({
generateDocx: vi.fn().mockResolvedValue(new Blob([new Uint8Array(8)], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' })),
generateDocx: vi
.fn()
.mockResolvedValue(
new Blob([new Uint8Array(8)], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
})
),
}));
import { ipc } from '@/lib/ipc';
@@ -31,8 +37,15 @@ describe('ExportDocxDialog', () => {
}));
(ipc.file.writeBuffer as any).mockResolvedValue({ ok: true });
useSettingsStore.setState(useSettingsStore.getInitialState());
useFileStore.setState({ activeTabId: '/test.md', openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }] } as any);
useEditorStore.setState({ buffers: new Map([['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }]]) } as any);
useFileStore.setState({
activeTabId: '/test.md',
openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }],
} as any);
useEditorStore.setState({
buffers: new Map([
['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }],
]),
} as any);
});
it('renders with standard template selected by default', () => {
@@ -25,8 +25,15 @@ describe('ExportHtmlDialog', () => {
}));
(ipc.file.writeBuffer as any).mockResolvedValue({ ok: true });
useSettingsStore.setState(useSettingsStore.getInitialState());
useFileStore.setState({ activeTabId: '/test.md', openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }] } as any);
useEditorStore.setState({ buffers: new Map([['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }]]) } as any);
useFileStore.setState({
activeTabId: '/test.md',
openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }],
} as any);
useEditorStore.setState({
buffers: new Map([
['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }],
]),
} as any);
});
it('renders with default github highlight style', () => {
@@ -22,8 +22,15 @@ describe('ExportPdfDialog', () => {
localStorage.clear();
vi.clearAllMocks();
useSettingsStore.setState(useSettingsStore.getInitialState());
useFileStore.setState({ activeTabId: '/test.md', openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }] } as any);
useEditorStore.setState({ buffers: new Map([['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }]]) } as any);
useFileStore.setState({
activeTabId: '/test.md',
openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }],
} as any);
useEditorStore.setState({
buffers: new Map([
['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }],
]),
} as any);
});
it('renders with default PDF options from settings', () => {
@@ -64,7 +64,10 @@ describe('FindInFilesDialog', () => {
});
it('shows an error banner when search fails', async () => {
(ipc.file.search as any).mockResolvedValueOnce({ ok: false, error: { code: 'E', message: 'regex invalid' } });
(ipc.file.search as any).mockResolvedValueOnce({
ok: false,
error: { code: 'E', message: 'regex invalid' },
});
render(<FindInFilesDialog />);
await userEvent.paste('[invalid', { initialSelectionStart: 0, initialSelectionEnd: 0 });
await userEvent.click(screen.getByRole('button', { name: /search/i }));
+1 -1
View File
@@ -29,4 +29,4 @@ describe('ModalLayer', () => {
expect(screen.queryByText(/about markdownconverter/i)).not.toBeInTheDocument();
expect(screen.getByText(/settings/i)).toBeInTheDocument();
});
});
});
@@ -55,4 +55,4 @@ describe('SettingsSheet', () => {
await userEvent.click(screen.getByRole('button', { name: /reset/i }));
expect(useSettingsStore.getState().fontSize).toBe(14);
});
});
});
@@ -33,4 +33,4 @@ describe('TableGeneratorDialog', () => {
render(<TableGeneratorDialog />);
expect(screen.getByRole('button', { name: /copy/i })).toBeInTheDocument();
});
});
});
@@ -47,7 +47,7 @@ describe('WelcomeDialog', () => {
// Effects that fire the warning run in a microtask; one tick is enough.
await Promise.resolve();
const offending = warnings.filter((w) =>
/Missing\s+`?Description`?|aria-describedby=\{undefined\}/.test(w),
/Missing\s+`?Description`?|aria-describedby=\{undefined\}/.test(w)
);
expect(offending).toEqual([]);
} finally {
@@ -7,7 +7,13 @@ import { useEditorStore } from '@/stores/editor-store';
import { useSettingsStore } from '@/stores/settings-store';
vi.mock('@/lib/docx-export', () => ({
generateDocx: vi.fn().mockResolvedValue(new Blob([new Uint8Array([1, 2, 3])], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' })),
generateDocx: vi
.fn()
.mockResolvedValue(
new Blob([new Uint8Array([1, 2, 3])], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
})
),
}));
vi.mock('@/lib/toast', () => ({
@@ -37,8 +43,15 @@ describe('WordExportDialog', () => {
localStorage.clear();
vi.clearAllMocks();
useSettingsStore.setState(useSettingsStore.getInitialState());
useFileStore.setState({ activeTabId: '/test.md', openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }] } as any);
useEditorStore.setState({ buffers: new Map([['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }]]) } as any);
useFileStore.setState({
activeTabId: '/test.md',
openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }],
} as any);
useEditorStore.setState({
buffers: new Map([
['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }],
]),
} as any);
(ipc.app.showSaveDialog as any).mockResolvedValue({ ok: true, data: '/out.docx' });
(ipc.file.writeBuffer as any).mockResolvedValue({ ok: true });
});
@@ -58,14 +71,20 @@ describe('WordExportDialog', () => {
});
it('shows error message on write failure', async () => {
(ipc.file.writeBuffer as any).mockResolvedValue({ ok: false, error: { code: 'E', message: 'write failed' } });
(ipc.file.writeBuffer as any).mockResolvedValue({
ok: false,
error: { code: 'E', message: 'write failed' },
});
render(<WordExportDialog sourcePath="/test.md" />);
await userEvent.click(screen.getByRole('button', { name: /^export$/i }));
expect(await screen.findByText(/write failed/i)).toBeInTheDocument();
});
it('switches to custom template path when "Custom" is selected', async () => {
useSettingsStore.setState({ ...useSettingsStore.getInitialState(), docxCustomTemplatePath: '/my.dotx' });
useSettingsStore.setState({
...useSettingsStore.getInitialState(),
docxCustomTemplatePath: '/my.dotx',
});
render(<WordExportDialog sourcePath="/test.md" />);
expect(screen.getByText(/\/my\.dotx/)).toBeInTheDocument();
});
+13 -2
View File
@@ -15,7 +15,13 @@ vi.mock('@/lib/ipc', () => ({
describe('FileTree', () => {
beforeEach(() => {
useFileStore.setState({ tree: null, rootPath: null, expanded: new Set(), openTabs: [], activeTabId: null });
useFileStore.setState({
tree: null,
rootPath: null,
expanded: new Set(),
openTabs: [],
activeTabId: null,
});
});
it('renders nothing when tree is null', () => {
@@ -66,7 +72,12 @@ describe('FileTree', () => {
isDirectory: true,
loaded: true,
children: [
{ name: 'index.ts', path: '/project/src/index.ts', isDirectory: false, children: null },
{
name: 'index.ts',
path: '/project/src/index.ts',
isDirectory: false,
children: null,
},
],
},
],
@@ -55,7 +55,9 @@ describe('GitStatusPanel', () => {
useFileStore.setState({ rootPath: '/project' } as any);
render(<GitStatusPanel />);
// The helper text appears in a <p> element distinct from the error heading
expect(await screen.findByText('Not a git repository, or git not installed.')).toBeInTheDocument();
expect(
await screen.findByText('Not a git repository, or git not installed.')
).toBeInTheDocument();
});
it('opens file on click', async () => {
@@ -70,4 +72,4 @@ describe('GitStatusPanel', () => {
await userEvent.click(row);
expect(openFile).toHaveBeenCalledWith('/project/a.md');
});
});
});
+10 -2
View File
@@ -20,7 +20,13 @@ vi.mock('@/lib/ipc', () => ({
describe('Sidebar', () => {
beforeEach(() => {
useFileStore.setState({ tree: null, rootPath: null, expanded: new Set(), openTabs: [], activeTabId: null });
useFileStore.setState({
tree: null,
rootPath: null,
expanded: new Set(),
openTabs: [],
activeTabId: null,
});
useEditorStore.setState({ buffers: new Map(), activeId: null });
});
@@ -46,7 +52,9 @@ describe('Sidebar', () => {
path: '/project',
isDirectory: true,
loaded: true,
children: [{ name: 'README.md', path: '/project/README.md', isDirectory: false, children: null }],
children: [
{ name: 'README.md', path: '/project/README.md', isDirectory: false, children: null },
],
},
rootPath: '/project',
});
+1 -1
View File
@@ -37,4 +37,4 @@ describe('ThemeToggle', () => {
await userEvent.click(btn);
expect(document.documentElement.classList.contains('light')).toBe(true);
});
});
});
+4 -2
View File
@@ -22,7 +22,9 @@ describe('PrintPreview', () => {
openTabs: [{ id: '/test.md', path: '/test.md', title: 'test.md', dirty: false }],
} as any);
useEditorStore.setState({
buffers: new Map([['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }]]),
buffers: new Map([
['/test.md', { id: '/test.md', path: '/test.md', content: '# hi', dirty: false }],
]),
} as any);
});
@@ -46,4 +48,4 @@ describe('PrintPreview', () => {
await userEvent.click(screen.getByRole('button', { name: /close/i }));
expect(onClose).toHaveBeenCalledTimes(1);
});
});
});
+1 -1
View File
@@ -31,4 +31,4 @@ describe('ReplPanel', () => {
await new Promise((r) => setTimeout(r, 400));
expect(screen.getByRole('heading', { name: /hello/i })).toBeInTheDocument();
});
});
});
+1 -1
View File
@@ -21,4 +21,4 @@ describe('Button', () => {
const btn = screen.getByRole('button');
expect(btn.className).toContain('bg-primary');
});
});
});
+1 -1
View File
@@ -10,4 +10,4 @@ describe('Checkbox', () => {
await userEvent.click(screen.getByRole('checkbox', { name: /agree/i }));
expect(onCheckedChange).toHaveBeenCalledWith(true);
});
});
});
+1 -1
View File
@@ -27,4 +27,4 @@ describe('Dialog', () => {
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByText(/title/i)).toBeInTheDocument();
});
});
});
+9 -2
View File
@@ -3,7 +3,14 @@ import { render, screen } from '@testing-library/react';
import { useForm, FormProvider } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form';
import {
Form,
FormField,
FormItem,
FormLabel,
FormControl,
FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
const schema = z.object({ name: z.string().min(2) });
@@ -39,4 +46,4 @@ describe('Form', () => {
render(<Harness />);
expect(screen.getByLabelText(/name/i)).toBeInTheDocument();
});
});
});
+1 -1
View File
@@ -11,4 +11,4 @@ describe('Input', () => {
await userEvent.type(input, 'a');
expect(onChange).toHaveBeenCalled();
});
});
});
+1 -1
View File
@@ -26,4 +26,4 @@ describe('Select', () => {
await userEvent.click(screen.getByRole('combobox', { name: /fruit/i }));
expect(screen.getByRole('option', { name: /apple/i })).toBeInTheDocument();
});
});
});
+1 -1
View File
@@ -26,4 +26,4 @@ describe('Sheet', () => {
await userEvent.click(screen.getByRole('button', { name: /open/i }));
expect(screen.getByRole('dialog')).toBeInTheDocument();
});
});
});
+1 -1
View File
@@ -14,4 +14,4 @@ describe('Toaster', () => {
// but the test should not throw
expect(container).toBeDefined();
});
});
});
+1 -1
View File
@@ -10,4 +10,4 @@ describe('Switch', () => {
await userEvent.click(screen.getByRole('switch', { name: /airplane/i }));
expect(onCheckedChange).toHaveBeenCalledWith(true);
});
});
});
+1 -1
View File
@@ -19,4 +19,4 @@ describe('Tabs', () => {
await userEvent.click(screen.getByRole('tab', { name: /two/i }));
expect(screen.getByText(/content two/i)).toBeVisible();
});
});
});
+1 -1
View File
@@ -9,4 +9,4 @@ describe('Textarea', () => {
expect(ta.tagName).toBe('TEXTAREA');
expect(ta).toHaveValue('hello');
});
});
});