useSettings error handling
This commit is contained in:
parent
2d0d91cd2e
commit
2f9845338a
@ -63,4 +63,18 @@ describe('useSettings', () => {
|
||||
expect(result.current.settings).toEqual(updatedSettings);
|
||||
expect(result.current.showSponsorInfo).toBe(false);
|
||||
});
|
||||
|
||||
it('handles errors when fetching settings', async () => {
|
||||
const mockError = new Error('Failed to fetch');
|
||||
(api.getSettings as any).mockRejectedValue(mockError);
|
||||
|
||||
const { result } = renderHook(() => useSettings());
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.error).toEqual(mockError);
|
||||
});
|
||||
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.settings).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,29 +3,41 @@ import type { AppSettings } from '../../shared/types';
|
||||
import * as api from '../api';
|
||||
|
||||
let settingsCache: AppSettings | null = null;
|
||||
let subscribers: Set<(settings: AppSettings) => void> = new Set();
|
||||
let settingsError: Error | null = null;
|
||||
let subscribers: Set<(settings: AppSettings | null, error: Error | null) => void> = new Set();
|
||||
let isFetching = false;
|
||||
|
||||
export function useSettings() {
|
||||
const [settings, setSettings] = useState<AppSettings | null>(settingsCache);
|
||||
const [error, setError] = useState<Error | null>(settingsError);
|
||||
|
||||
useEffect(() => {
|
||||
if (settingsCache) {
|
||||
setSettings(settingsCache);
|
||||
}
|
||||
if (settingsError) {
|
||||
setError(settingsError);
|
||||
}
|
||||
|
||||
const handleUpdate = (newSettings: AppSettings) => {
|
||||
const handleUpdate = (newSettings: AppSettings | null, newError: Error | null) => {
|
||||
setSettings(newSettings);
|
||||
setError(newError);
|
||||
};
|
||||
|
||||
subscribers.add(handleUpdate);
|
||||
|
||||
if (!settingsCache && !isFetching) {
|
||||
isFetching = true;
|
||||
settingsError = null;
|
||||
api.getSettings()
|
||||
.then((data) => {
|
||||
settingsCache = data;
|
||||
subscribers.forEach(sub => sub(data));
|
||||
settingsError = null;
|
||||
subscribers.forEach(sub => sub(data, null));
|
||||
})
|
||||
.catch((err) => {
|
||||
settingsError = err instanceof Error ? err : new Error(String(err));
|
||||
subscribers.forEach(sub => sub(settingsCache, settingsError));
|
||||
})
|
||||
.finally(() => {
|
||||
isFetching = false;
|
||||
@ -39,11 +51,19 @@ export function useSettings() {
|
||||
|
||||
const refreshSettings = async () => {
|
||||
isFetching = true;
|
||||
settingsError = null;
|
||||
subscribers.forEach(sub => sub(settingsCache, null));
|
||||
|
||||
try {
|
||||
const data = await api.getSettings();
|
||||
settingsCache = data;
|
||||
subscribers.forEach(sub => sub(data));
|
||||
settingsError = null;
|
||||
subscribers.forEach(sub => sub(data, null));
|
||||
return data;
|
||||
} catch (err) {
|
||||
settingsError = err instanceof Error ? err : new Error(String(err));
|
||||
subscribers.forEach(sub => sub(settingsCache, settingsError));
|
||||
throw settingsError;
|
||||
} finally {
|
||||
isFetching = false;
|
||||
}
|
||||
@ -51,7 +71,8 @@ export function useSettings() {
|
||||
|
||||
return {
|
||||
settings,
|
||||
isLoading: !settings && isFetching,
|
||||
error,
|
||||
isLoading: !settings && isFetching && !error,
|
||||
showSponsorInfo: settings?.showSponsorInfo ?? true,
|
||||
refreshSettings,
|
||||
};
|
||||
@ -60,6 +81,7 @@ export function useSettings() {
|
||||
/** @internal For testing only */
|
||||
export function _resetSettingsCache() {
|
||||
settingsCache = null;
|
||||
settingsError = null;
|
||||
isFetching = false;
|
||||
subscribers.clear();
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ vi.mock('../../pipeline/index.js', () => {
|
||||
getPipelineStatus: vi.fn(() => ({ isRunning: false })),
|
||||
subscribeToProgress: vi.fn((listener: (data: unknown) => void) => {
|
||||
listener(progress);
|
||||
return () => {};
|
||||
return () => { };
|
||||
}),
|
||||
};
|
||||
});
|
||||
@ -54,6 +54,13 @@ vi.mock('../../services/visa-sponsors/index.js', () => ({
|
||||
searchSponsors: vi.fn(),
|
||||
getOrganizationDetails: vi.fn(),
|
||||
downloadLatestCsv: vi.fn(),
|
||||
calculateSponsorMatchSummary: vi.fn((results) => {
|
||||
if (!results || results.length === 0) return { sponsorMatchScore: 0, sponsorMatchNames: null };
|
||||
return {
|
||||
sponsorMatchScore: results[0].score,
|
||||
sponsorMatchNames: JSON.stringify(results.map((r: any) => r.sponsor.organisationName))
|
||||
};
|
||||
}),
|
||||
}));
|
||||
|
||||
const originalEnv = { ...process.env };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user