javascript - 关于嵌套 try catch 语句和错误处理的问题
由于在管道中不同的包装器和相互传递的东西,我正在处理多个嵌套的 try catch 语句。
我正在尝试通过模拟响应并在数据最终传递到某个地方时调用 .json() 并抛出下面定义形状的错误,从而在名为 put 的函数的 catch 块上获得测试覆盖率。
it('hits the catch', async () => {
fetch.mockImplementation(() =>
Promise.resolve({
ok: true,
json: () => {
throw { type: 'error', message: 'hit the catch' }
},
})
)
expect(
await put({
path: '/script/1',
body: {
name: 'newName',
},
})
).toThrow({
message: 'hit the catch',
type: 'error',
})
})
这个函数反过来调用一个客户端函数:
export const put = async <I, R>({ path, body }: { path: string; body: I }) => {
try {
return client<I>(getServiceUrl(path), 'PUT', getServiceHeaders(token), body)
} catch (e) {
throw handleClientError(e)
// return handleClientError(e)
}
}
客户端函数是 fetch 的一个包装器:
export const client = async <I>(
url: string,
method: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE',
headers: HeadersInit,
body?: I
): Promise<ServiceResonse<I>> => {
try {
const res: Response = await fetch(url, {
method,
headers,
body: JSON.stringify(body),
})
return getServiceResponse(res)
} catch (e) {
throw handleClientError(e)
// return handleClientError(e)
}
}
这里还调用了各种辅助函数:
export const getServiceHeaders = (token: string = ''): HeadersInit => {
try {
if (token) {
return {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token,
}
} else {
return {
'Content-Type': 'application/json',
}
}
} catch (e) {
const msg = 'Error getting service headers ' + JSON.stringify(e)
console.error(msg) //shouldn't ever happen
throw new Error(msg)
}
}
export const getServiceResponse = async <T>(
response: Response
): Promise<ServiceResonse<T>> => {
try {
const data = await response.json()
if (!response.ok) {
let error = {
code: (data && data.code) || 'error',
message:
(data && data.message) ||
response.statusText ||
'Unkown Error x03391aa00',
invalid: null,
}
switch (response.status) {
case 400:
if (error.code == 'invalid') {
return (error.invalid = ((data && data.errors) || []).reduce(
(items: RequestErrorResponseFields, i: APIResponseErrorItem) => {
items[i.field] = i.message
return items
},
{}
))
}
break
case 401:
// TODO handle error)
return { type: 'error', fields: {}, message: 'Invalid Token' }
break
}
return Promise.reject(error)
} else {
return data
}
} catch (e) {
throw e
}
}
export const getServiceUrl = (
path: string,
options: { [k: string]: string | number } = {}
): string => {
if (typeof path !== 'string') throw new Error('path must be of type string')
if (typeof options !== 'object')
throw new Error('options must be of type object')
const query = Object.keys(options)
.map(k => k + '=' + options[k])
.join('&')
//todo move to general configuration file, still use process.env
const baseUrl = process.env.API_URL || 'http://localhost/ipa'
return `${baseUrl}${path}${query.length ? '?' + query : ''}`
}
export const handleClientError = (
err: { message?: string } | RequestErrorResponse
) => {
if ('type' in err) {
throw err
// return Promise.reject(err)
} else {
throw {
code: 'error',
message: err.message || 'Unkown - 0x39aef3991',
errors: [],
}
// return Promise.reject({
// code: 'error',
// message: err.message || 'Unkown - 0x39aef3991',
// errors: [],
// })
}
}
我正在尝试通过强制抛出异常并将其传递到 catch 块来获得 put 函数中 catch 块的测试覆盖率,但我似乎无法让它到达。我不确定应在何时强制抛出异常,然后如何传递并进行测试。有人有关于我应该如何处理或我漏掉了什么的建议吗?
答案#1
在你的 async put 函数中,你有一行返回一个 Promise 的代码:
return client(getServiceUrl(path), 'PUT', getServiceHeaders(token), body)
你在这一行周围使用的 try/catch 块可以捕获同步抛出的错误,但不能捕获异步错误。如果你想使用 try/catch 块来捕获这些异步错误,你需要添加一个 await 语句:
export const put = async <I, R>({ path, body }: { path: string; body: I }) => {
try {
return await client<I>(getServiceUrl(path), 'PUT', getServiceHeaders(token), body)
} catch (e) {
throw handleClientError(e)
// return handleClientError(e)
}
}
或者,你可以使用常规的 promise catch:
return await client<I>(getServiceUrl(path), 'PUT', getServiceHeaders(token), body).catch(handleClientError)
(注意:我没有完全查看代码——里面可能还有更多存在异步问题的地方)
