mirror of
https://github.com/zoriya/v10.git
synced 2026-08-08 07:07:10 +00:00
feat(store): queue task refactor (#287)
This commit is contained in:
@@ -1 +1,2 @@
|
||||
export { composeCallbacks } from './compose-callbacks';
|
||||
export { tryCatch } from './try-catch';
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { tryCatch } from '../try-catch';
|
||||
|
||||
describe('tryCatch', () => {
|
||||
it('returns undefined if fn is undefined', () => {
|
||||
expect(tryCatch(undefined)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns undefined if fn is null', () => {
|
||||
// @ts-expect-error - testing null input
|
||||
expect(tryCatch(null)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('calls the wrapped function with arguments', () => {
|
||||
const fn = vi.fn((a: number, b: number) => a + b);
|
||||
const wrapped = tryCatch(fn);
|
||||
|
||||
const result = wrapped?.(1, 2);
|
||||
|
||||
expect(fn).toHaveBeenCalledWith(1, 2);
|
||||
expect(result).toBe(3);
|
||||
});
|
||||
|
||||
it('returns the function result when no error', () => {
|
||||
const fn = () => 'result';
|
||||
const wrapped = tryCatch(fn);
|
||||
|
||||
expect(wrapped?.()).toBe('result');
|
||||
});
|
||||
|
||||
it('catches errors and calls onError', () => {
|
||||
const error = new Error('test error');
|
||||
const fn = () => {
|
||||
throw error;
|
||||
};
|
||||
const onError = vi.fn();
|
||||
|
||||
const wrapped = tryCatch(fn, onError);
|
||||
const result = wrapped?.();
|
||||
|
||||
expect(onError).toHaveBeenCalledWith(error);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('uses console.error as default onError', () => {
|
||||
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const error = new Error('test error');
|
||||
const fn = () => {
|
||||
throw error;
|
||||
};
|
||||
|
||||
const wrapped = tryCatch(fn);
|
||||
wrapped?.();
|
||||
|
||||
expect(consoleSpy).toHaveBeenCalledWith(error);
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('does not throw when wrapped function throws', () => {
|
||||
const fn = () => {
|
||||
throw new Error('should not propagate');
|
||||
};
|
||||
const onError = vi.fn();
|
||||
|
||||
const wrapped = tryCatch(fn, onError);
|
||||
|
||||
expect(() => wrapped?.()).not.toThrow();
|
||||
});
|
||||
|
||||
it('preserves function type signature', () => {
|
||||
const fn = (name: string, age: number): string => `${name} is ${age}`;
|
||||
const wrapped = tryCatch(fn);
|
||||
|
||||
// TypeScript should infer correct types
|
||||
const result: string | undefined = wrapped?.('Alice', 30);
|
||||
expect(result).toBe('Alice is 30');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Wrap a function to catch and handle errors instead of throwing.
|
||||
*
|
||||
* @param fn - Function to wrap (can be undefined)
|
||||
* @param onError - Error handler (defaults to console.error)
|
||||
* @returns Wrapped function that never throws, or undefined if fn is undefined
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const safeFn = tryCatch(riskyFn, (e) => logger.error(e));
|
||||
* safeFn?.(); // Never throws
|
||||
* ```
|
||||
*/
|
||||
export function tryCatch<T extends (...args: any[]) => unknown>(
|
||||
fn: T | undefined,
|
||||
onError: (error: unknown) => void = console.error,
|
||||
): T | undefined {
|
||||
if (!fn) return undefined;
|
||||
|
||||
return ((...args: Parameters<T>) => {
|
||||
try {
|
||||
return fn(...args);
|
||||
} catch (error) {
|
||||
onError(error);
|
||||
return undefined;
|
||||
}
|
||||
}) as T;
|
||||
}
|
||||
Reference in New Issue
Block a user