expect(() => store.throws()).toThrowError('fail')
})
+ it('throws errors', () => {
+ const store = useStore()
+ expect(() => store.throws()).toThrowError('fail')
+ })
+
+ it('can avoid errors to propagate', () => {
+ const store = useStore()
+ store.$onAction(({ onError }) => {
+ onError(() => false)
+ })
+ expect(() => store.throws()).not.toThrowError('fail')
+ })
+
+ it('can avoid async errors to propagate', async () => {
+ const store = useStore()
+ store.$onAction(({ onError }) => {
+ onError(() => false)
+ })
+ await expect(store.rejects()).resolves.toBe(undefined)
+ })
+
it('throws async errors', async () => {
const store = useStore()
expect.assertions(1)
await expect(store.rejects()).rejects.toBe('fail')
})
+
+ it('can catch async errors', async () => {
+ const store = useStore()
+ expect.assertions(3)
+ const spy = jest.fn()
+ await expect(store.rejects().catch(spy)).resolves.toBe(undefined)
+ expect(spy).toHaveBeenCalledTimes(1)
+ expect(spy).toHaveBeenCalledWith('fail')
+ })
+
+ it('can override the returned value', () => {
+ const store = useStore()
+ expect.assertions(2)
+ store.$onAction(({ after }) => {
+ // @ts-expect-error: cannot return a string because no action returns a string
+ after((v) => {
+ expect(v).toBe(false)
+ return 'hello'
+ })
+ })
+ expect(store.toggle()).toBe('hello')
+ })
+
+ it('can override the resolved value', async () => {
+ const store = useStore()
+ expect.assertions(2)
+ store.$onAction(({ after }) => {
+ // @ts-expect-error: cannot return a string because no action returns a string
+ after((v) => {
+ expect(v).toBe(false)
+ return 'hello'
+ })
+ })
+ await expect(store.getNonA()).resolves.toBe('hello')
+ })
+
+ it('can override the resolved value with a promise', async () => {
+ const store = useStore()
+ expect.assertions(2)
+ store.$onAction(({ after }) => {
+ // @ts-expect-error: cannot return a string because no action returns a string
+ after(async (v) => {
+ expect(v).toBe(false)
+ return 'hello'
+ })
+ })
+ await expect(store.getNonA()).resolves.toBe('hello')
+ })
})
setActivePinia(pinia)
const args = Array.from(arguments)
- let afterCallback: (resolvedReturn: any) => void = noop
- let onErrorCallback: (error: unknown) => void = noop
+ let afterCallback: (resolvedReturn: any) => any = noop
+ let onErrorCallback: (error: unknown) => unknown = noop
function after(callback: typeof afterCallback) {
afterCallback = callback
}
let ret: any
try {
ret = action.apply(this || store, args)
- Promise.resolve(ret).then(afterCallback).catch(onErrorCallback)
+ // Promise.resolve(ret).then(afterCallback).catch(onErrorCallback)
} catch (error) {
- onErrorCallback(error)
- throw error
+ if (onErrorCallback(error) !== false) {
+ throw error
+ }
}
- return ret
+ if (ret instanceof Promise) {
+ return ret
+ .then((value) => {
+ const newRet = afterCallback(value)
+ // allow the afterCallback to override the return value
+ return newRet === undefined ? value : newRet
+ })
+ .catch((error) => {
+ if (onErrorCallback(error) !== false) {
+ return Promise.reject(error)
+ }
+ })
+ }
+
+ const newRet = afterCallback(ret)
+
+ return newRet === undefined ? ret : newRet
}
}
args: A[Name] extends _Method ? Parameters<A[Name]> : unknown[]
/**
- * Sets up a hook once the action is finished. It receives the return value of
- * the action, if it's a Promise, it will be unwrapped.
+ * Sets up a hook once the action is finished. It receives the return value
+ * of the action, if it's a Promise, it will be unwrapped. Can return a
+ * value (other than `undefined`) to **override** the returned value.
*/
after: (
callback: A[Name] extends _Method
- ? (resolvedReturn: UnwrapPromise<ReturnType<A[Name]>>) => void
+ ? (
+ resolvedReturn: UnwrapPromise<ReturnType<A[Name]>>
+ // allow the after callback to override the return value
+ ) => void | ReturnType<A[Name]> | UnwrapPromise<ReturnType<A[Name]>>
: () => void
) => void
/**
- * Sets up a hook if the action fails.
+ * Sets up a hook if the action fails. Return `false` to catch the error and
+ * stop it fro propagating.
*/
- onError: (callback: (error: unknown) => void) => void
+ onError: (callback: (error: unknown) => unknown | false) => void
}
}[keyof A]