+ );
+ }
+}
+
+export default ErrorBoundary;
diff --git a/src/renderer/i18n/locales/de/common.json b/src/renderer/i18n/locales/de/common.json
index 131c4cc..04f3838 100644
--- a/src/renderer/i18n/locales/de/common.json
+++ b/src/renderer/i18n/locales/de/common.json
@@ -123,6 +123,11 @@
"noFilesSelectedForProcessing": "Es sind keine Dateien zur Verarbeitung ausgewählt. Wechsle zum Quell-Tab und wähle Dateien aus.",
"refreshFailed": "Beim Aktualisieren des Inhalts ist ein Fehler aufgetreten. Details in der Konsole.",
"noProcessedContentToSave": "Kein verarbeiteter Inhalt zum Speichern vorhanden.",
- "saveFailed": "Beim Speichern der Datei ist ein Fehler aufgetreten. Details in der Konsole."
+ "saveFailed": "Beim Speichern der Datei ist ein Fehler aufgetreten. Details in der Konsole.",
+ "rendererRootCrashedTitle": "Die App hat einen unerwarteten Fehler festgestellt.",
+ "rendererRootCrashedDescription": "Bitte erneut versuchen. Wenn das erneut passiert, starte die App neu.",
+ "tabCrashedTitle": "Dieser Tab konnte nicht gerendert werden.",
+ "tabCrashedDescription": "Versuche diese Ansicht erneut. Falls das Problem bleibt, wechsle den Tab und versuche es noch einmal.",
+ "retryRender": "Erneut versuchen"
}
}
diff --git a/src/renderer/i18n/locales/en/common.json b/src/renderer/i18n/locales/en/common.json
index 516c3b4..1acf3d3 100644
--- a/src/renderer/i18n/locales/en/common.json
+++ b/src/renderer/i18n/locales/en/common.json
@@ -123,6 +123,11 @@
"noFilesSelectedForProcessing": "No files are selected for processing. Please go to the Source tab and select files.",
"refreshFailed": "An error occurred while refreshing content. Check the console for details.",
"noProcessedContentToSave": "No processed content to save.",
- "saveFailed": "An error occurred while saving the file. Check the console for details."
+ "saveFailed": "An error occurred while saving the file. Check the console for details.",
+ "rendererRootCrashedTitle": "The app hit an unexpected error.",
+ "rendererRootCrashedDescription": "Please retry. If this keeps happening, restart the app.",
+ "tabCrashedTitle": "This tab failed to render.",
+ "tabCrashedDescription": "Retry this view. If the issue persists, switch tabs and try again.",
+ "retryRender": "Retry"
}
}
diff --git a/src/renderer/i18n/locales/es/common.json b/src/renderer/i18n/locales/es/common.json
index 677d6e8..34413c8 100644
--- a/src/renderer/i18n/locales/es/common.json
+++ b/src/renderer/i18n/locales/es/common.json
@@ -123,6 +123,11 @@
"noFilesSelectedForProcessing": "No hay archivos seleccionados para procesar. Ve a la pestaña Fuente y selecciona archivos.",
"refreshFailed": "Se produjo un error al actualizar el contenido. Revisa la consola para más detalles.",
"noProcessedContentToSave": "No hay contenido procesado para guardar.",
- "saveFailed": "Se produjo un error al guardar el archivo. Revisa la consola para más detalles."
+ "saveFailed": "Se produjo un error al guardar el archivo. Revisa la consola para más detalles.",
+ "rendererRootCrashedTitle": "La aplicación encontró un error inesperado.",
+ "rendererRootCrashedDescription": "Intenta de nuevo. Si vuelve a ocurrir, reinicia la aplicación.",
+ "tabCrashedTitle": "Esta pestaña no se pudo renderizar.",
+ "tabCrashedDescription": "Vuelve a intentarlo en esta vista. Si persiste, cambia de pestaña e inténtalo otra vez.",
+ "retryRender": "Reintentar"
}
}
diff --git a/src/renderer/i18n/locales/fr/common.json b/src/renderer/i18n/locales/fr/common.json
index 3118008..db31627 100644
--- a/src/renderer/i18n/locales/fr/common.json
+++ b/src/renderer/i18n/locales/fr/common.json
@@ -123,6 +123,11 @@
"noFilesSelectedForProcessing": "Aucun fichier sélectionné pour le traitement. Allez dans l'onglet Source et sélectionnez des fichiers.",
"refreshFailed": "Une erreur s'est produite lors de l'actualisation du contenu. Consultez la console pour plus de détails.",
"noProcessedContentToSave": "Aucun contenu traité à enregistrer.",
- "saveFailed": "Une erreur s'est produite lors de l'enregistrement du fichier. Consultez la console pour plus de détails."
+ "saveFailed": "Une erreur s'est produite lors de l'enregistrement du fichier. Consultez la console pour plus de détails.",
+ "rendererRootCrashedTitle": "L'application a rencontré une erreur inattendue.",
+ "rendererRootCrashedDescription": "Réessayez. Si le problème persiste, redémarrez l'application.",
+ "tabCrashedTitle": "Cet onglet n'a pas pu être affiché.",
+ "tabCrashedDescription": "Réessayez cette vue. Si le problème persiste, changez d'onglet puis recommencez.",
+ "retryRender": "Réessayer"
}
}
diff --git a/tests/catalog.md b/tests/catalog.md
index 52d00f2..4087878 100644
--- a/tests/catalog.md
+++ b/tests/catalog.md
@@ -25,6 +25,7 @@ Purpose: quick map of what is covered, why it exists, and which command to run.
| ---------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `tests/unit/components/app.test.tsx` | `src/renderer/components/App.tsx` | Tab switching, config load, directory selection, processing flow, error handling |
| `tests/unit/components/app-source-tab-activity.test.tsx` | `src/renderer/components/App.tsx` + `src/renderer/components/SourceTab.tsx` | Guards against hidden-tab background token counting after tab switch |
+| `tests/unit/components/error-boundary.test.tsx` | `src/renderer/components/ErrorBoundary.tsx` | Child render failure capture, fallback rendering, reset-key recovery, and retry callback behavior |
| `tests/unit/components/config-tab.test.tsx` | `src/renderer/components/ConfigTab.tsx` | Config toggles/inputs, dev-only provider surface gating, provider validation/connection wiring, provider-config preservation, directory picker trigger |
| `tests/unit/components/file-tree.test.tsx` | `src/renderer/components/FileTree.tsx` | Tree render, folder expand/collapse, select all, empty-state behavior |
| `tests/unit/components/language-selector.test.tsx` | `src/renderer/components/LanguageSelector.tsx` | Locale selector rendering, language switching, and localStorage persistence |
diff --git a/tests/unit/components/error-boundary.test.tsx b/tests/unit/components/error-boundary.test.tsx
new file mode 100644
index 0000000..9027efc
--- /dev/null
+++ b/tests/unit/components/error-boundary.test.tsx
@@ -0,0 +1,97 @@
+import React, { useState } from 'react';
+import { fireEvent, render, screen } from '@testing-library/react';
+
+import ErrorBoundary from '../../../src/renderer/components/ErrorBoundary';
+
+const ProblemChild = ({ shouldThrow }: { shouldThrow: boolean }) => {
+ if (shouldThrow) {
+ throw new Error('render boom');
+ }
+ return