fix: unified handling of editor reloading (#32)

Co-authored-by: hugo <hugoms@me.com>
This commit is contained in:
Georg Bauer
2026-03-04 09:28:20 +01:00
committed by GitHub
parent 32b66e1677
commit 08ef72a802
19 changed files with 633 additions and 239 deletions

View File

@@ -185,6 +185,7 @@ describe('Editor does not reset content on auto-save (cursor stability)', () =>
(window as any).electronAPI.meta.getCategories = vi.fn().mockReturnValue(neverSettles);
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
preferredEditorMode: 'markdown',
posts: [],
media: [],

View File

@@ -62,6 +62,7 @@ describe('Editor dashboard timeline', () => {
(window as any).electronAPI.app.setPreviewPostTarget = vi.fn().mockResolvedValue(undefined);
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
tabs: [],
activeTabId: null,
posts: [],

View File

@@ -155,6 +155,7 @@ describe('Editor metadata collapse', () => {
(window as any).electronAPI.meta.getCategories = vi.fn().mockReturnValue(neverSettles);
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
preferredEditorMode: 'wysiwyg',
posts: [],
media: [],

View File

@@ -165,6 +165,7 @@ describe('Editor visual mode persistence', () => {
(window as any).electronAPI.meta.getCategories = vi.fn().mockReturnValue(neverSettles);
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
preferredEditorMode: 'wysiwyg',
posts: [],
media: [],

View File

@@ -3,11 +3,16 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/react';
import { MenuEditorView } from '../../../src/renderer/components/MenuEditorView/MenuEditorView';
import { useAppStore } from '../../../src/renderer/store';
describe('MenuEditorView entry editor', () => {
beforeEach(() => {
vi.clearAllMocks();
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
});
(window as any).electronAPI = {
...(window as any).electronAPI,
menu: {

View File

@@ -86,6 +86,7 @@ describe('ScriptsView', () => {
};
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
panelVisible: false,
panelActiveTab: 'tasks',
panelOutputEntries: [],
@@ -437,4 +438,30 @@ describe('ScriptsView', () => {
expect(startTaskMock).not.toHaveBeenCalled();
});
});
it('defers loading until activeProject is set to avoid startup race condition', async () => {
useAppStore.setState({ activeProject: null });
const getMock = (window as any).electronAPI.scripts.get;
const { rerender } = render(<ScriptsView scriptId="script-1" />);
// Give the effect a chance to run
await vi.waitFor(() => {
expect(getMock).not.toHaveBeenCalled();
});
// Now simulate project context becoming available
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
});
// Re-render to pick up store change
rerender(<ScriptsView scriptId="script-1" />);
await vi.waitFor(() => {
expect(getMock).toHaveBeenCalledWith('script-1');
const textarea = screen.getByLabelText('Script Content') as HTMLTextAreaElement;
expect(textarea.value).toContain('print("hello")');
});
});
});

View File

@@ -2,11 +2,16 @@ import React from 'react';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { render, act, screen, fireEvent } from '@testing-library/react';
import { TagsView } from '../../../src/renderer/components/TagsView/TagsView';
import { useAppStore } from '../../../src/renderer/store';
describe('TagsView subscriptions', () => {
beforeEach(() => {
const onMock = vi.fn((_channel: string, _callback: (...args: unknown[]) => void) => vi.fn());
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
});
(window as any).electronAPI = {
...(window as any).electronAPI,
tags: {
@@ -66,6 +71,10 @@ describe('TagsView template dropdown', () => {
beforeEach(() => {
const onMock = vi.fn((_channel: string, _callback: (...args: unknown[]) => void) => vi.fn());
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
});
(window as any).electronAPI = {
...(window as any).electronAPI,
tags: {

View File

@@ -42,6 +42,10 @@ describe('TemplatesView', () => {
beforeEach(() => {
vi.clearAllMocks();
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
});
(window as any).electronAPI = {
...(window as any).electronAPI,
templates: {
@@ -208,4 +212,27 @@ describe('TemplatesView', () => {
expect(saveButton).toBeDisabled();
});
});
it('defers loading until activeProject is set to avoid startup race condition', async () => {
useAppStore.setState({ activeProject: null });
const getMock = (window as any).electronAPI.templates.get;
const { rerender } = render(<TemplatesView templateId="template-1" />);
await vi.waitFor(() => {
expect(getMock).not.toHaveBeenCalled();
});
useAppStore.setState({
activeProject: { id: 'project-1', name: 'Test', path: '/tmp/test' } as any,
});
rerender(<TemplatesView templateId="template-1" />);
await vi.waitFor(() => {
expect(getMock).toHaveBeenCalledWith('template-1');
const titleInput = screen.getByLabelText('Title') as HTMLInputElement;
expect(titleInput.value).toBe('Custom Post');
});
});
});