Files
bDS/tests/setup.ts
Georg Bauer b855d61524 Feature/post media translations (#42)
* chore: updated todo with translation ideas

* feat: first take at the implementation of translations

* fix: small addition for the translation feature

* feat: support language switching in the editor and preview

* feat: better handling of long bodies by not running them through a json envelope

* fix: unknown macros have better fallback

* feat: api for python to get translations

* fix: strip dumb prefix of content in translation

* feat: extend meta diff for translations

* feat: hook up translations to rebuild-from-disk

* feat: generation of the website prefers project language, falling back to canonical language

* fix: crashes during rendering

* feat: translation validation report

* fix: made the translation validation actually work

* chore: reorganization of menu

* fix: some topics cleanup

* chore: updated doc

* feat: translations for media

* feat: more aligned in UI/UX

* feat: edit translations possible

* chore: added full multi-language todo

* chore: updated todo for clarity

* feat: implementation of full multi-linguality

* fix: page creation creates pages

* fix: flags on every page

* fix: better prompt

* feat: made MCP server aware of language content

* feat: python tools for translations

* fix: better fill-in-translations

* fix: better prompt for translation. maybe.

* fix: losing posts from search due to translation process

* fix: translation validation handles in-db content and fill-in of missing translations fixed to flush

* fix: faster scanning for infilling of missing translations

* chore: updated agent instructions

* feat: calendar and tag cloud respect current language now

* fix: retries going up

* fix: got metadata-diff and rebuild into sync

* fix: extended meta-diff for timestamps

* fix: made website validation look at translated content, too

* fix: multi-lingual search

* chore: refactor Editor.tsx into two separate editors

* feat: do language detection when no explicit language given

---------

Co-authored-by: hugo <hugoms@me.com>
2026-03-09 14:43:18 +01:00

236 lines
6.0 KiB
TypeScript

/**
* Test setup file for Vitest
* Configures mocks and global test utilities
*/
import { vi, beforeEach, afterEach } from 'vitest';
import '@testing-library/jest-dom/vitest';
// Polyfill for IE-specific event methods that React DOM's input polyfill checks for
// jsdom doesn't implement these, but React tries to use them for IE compatibility
if (typeof Element !== 'undefined' && !Element.prototype.attachEvent) {
(Element.prototype as any).attachEvent = function() {};
(Element.prototype as any).detachEvent = function() {};
}
// Mock localStorage for Zustand persist middleware
const localStorageMock = (() => {
let store: Record<string, string> = {};
return {
getItem: vi.fn((key: string) => store[key] || null),
setItem: vi.fn((key: string, value: string) => {
store[key] = value;
}),
removeItem: vi.fn((key: string) => {
delete store[key];
}),
clear: vi.fn(() => {
store = {};
}),
get length() {
return Object.keys(store).length;
},
key: vi.fn((index: number) => Object.keys(store)[index] || null),
};
})();
Object.defineProperty(globalThis, 'localStorage', {
value: localStorageMock,
writable: true,
});
// Mock window.electronAPI for renderer tests
Object.defineProperty(globalThis, 'window', {
value: {
localStorage: localStorageMock,
electronAPI: {
git: {
checkAvailability: vi.fn(),
getRepoState: vi.fn(),
getStatus: vi.fn(),
getDiff: vi.fn(),
getDiffContent: vi.fn(),
getHistory: vi.fn(),
getFileHistory: vi.fn(),
init: vi.fn(),
},
posts: {
create: vi.fn(),
update: vi.fn(),
delete: vi.fn(),
get: vi.fn(),
getAll: vi.fn(),
getByStatus: vi.fn(),
publish: vi.fn(),
rebuildFromFiles: vi.fn(),
search: vi.fn(),
filter: vi.fn(),
getTags: vi.fn(),
getCategories: vi.fn(),
getByYearMonth: vi.fn(),
getLinksTo: vi.fn(),
getLinkedBy: vi.fn(),
rebuildLinks: vi.fn(),
},
media: {
import: vi.fn(),
importDialog: vi.fn(),
update: vi.fn(),
delete: vi.fn(),
get: vi.fn(),
getAll: vi.fn(),
rebuildFromFiles: vi.fn(),
getThumbnail: vi.fn(),
regenerateThumbnails: vi.fn(),
search: vi.fn(),
getUrl: vi.fn(),
getFilePath: vi.fn(),
getTranslation: vi.fn(),
getTranslations: vi.fn(),
upsertTranslation: vi.fn(),
deleteTranslation: vi.fn(),
},
sync: {
checkAvailability: vi.fn(),
getRepoState: vi.fn(),
getStatus: vi.fn(),
getHistory: vi.fn(),
getRemoteState: vi.fn(),
fetch: vi.fn(),
pull: vi.fn(),
push: vi.fn(),
commitAll: vi.fn(),
},
dropbox: {
configure: vi.fn(),
isConfigured: vi.fn(),
getStatus: vi.fn(),
syncAll: vi.fn(),
startWatching: vi.fn(),
stopWatching: vi.fn(),
startPolling: vi.fn(),
stopPolling: vi.fn(),
getConflicts: vi.fn(),
resolveConflict: vi.fn(),
getLastSyncTime: vi.fn(),
},
meta: {
getTags: vi.fn(),
getCategories: vi.fn(),
addTag: vi.fn(),
removeTag: vi.fn(),
addCategory: vi.fn(),
removeCategory: vi.fn(),
syncOnStartup: vi.fn(),
getProjectMetadata: vi.fn(),
setProjectMetadata: vi.fn(),
updateProjectMetadata: vi.fn(),
},
tasks: {
getAll: vi.fn(),
getRunning: vi.fn(),
cancel: vi.fn(),
clearCompleted: vi.fn(),
},
app: {
triggerMenuAction: vi.fn(),
getBlogmarkBookmarklet: vi.fn(),
copyToClipboard: vi.fn(),
notifyRendererReady: vi.fn(),
},
import: {
selectAndAnalyze: vi.fn(),
analyzeFile: vi.fn(),
selectUploadsFolder: vi.fn(),
},
importDefinitions: {
create: vi.fn(),
get: vi.fn(),
getAll: vi.fn(),
update: vi.fn(),
delete: vi.fn(),
},
templates: {
getEnabledByKind: vi.fn().mockResolvedValue([]),
getAll: vi.fn().mockResolvedValue([]),
get: vi.fn().mockResolvedValue(null),
create: vi.fn().mockResolvedValue(null),
update: vi.fn().mockResolvedValue(null),
delete: vi.fn().mockResolvedValue({ deleted: true }),
validate: vi.fn().mockResolvedValue({ valid: true, errors: [] }),
rebuildFromFiles: vi.fn().mockResolvedValue(undefined),
},
embeddings: {
findSimilar: vi.fn().mockResolvedValue([]),
computeSimilarities: vi.fn().mockResolvedValue({}),
},
on: vi.fn(() => () => {}),
},
},
writable: true,
});
// Mock Electron app module
vi.mock('electron', () => ({
app: {
getPath: vi.fn((name: string) => {
const paths: Record<string, string> = {
userData: '/mock/userData',
appData: '/mock/appData',
temp: '/mock/temp',
};
return paths[name] || '/mock/unknown';
}),
isPackaged: false,
quit: vi.fn(),
on: vi.fn(),
},
ipcMain: {
handle: vi.fn(),
on: vi.fn(),
removeHandler: vi.fn(),
},
ipcRenderer: {
invoke: vi.fn(),
on: vi.fn(),
send: vi.fn(),
},
BrowserWindow: vi.fn().mockImplementation(() => ({
loadURL: vi.fn(),
loadFile: vi.fn(),
on: vi.fn(),
webContents: {
send: vi.fn(),
openDevTools: vi.fn(),
},
isDestroyed: vi.fn(() => false),
})),
Menu: {
buildFromTemplate: vi.fn(),
setApplicationMenu: vi.fn(),
},
}));
// Reset mocks between tests
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.restoreAllMocks();
});
// Global test utilities
declare global {
// Add any global test utilities here
var testUtils: {
wait: (ms: number) => Promise<void>;
createMockDate: (date: string) => Date;
};
}
globalThis.testUtils = {
wait: (ms: number) => new Promise(resolve => setTimeout(resolve, ms)),
createMockDate: (date: string) => new Date(date),
};