gpt4 book ai didi

reactjs - Redux 使用 jest、nock、axios 和 jsdom 测试 multipart/form-data

转载 作者:行者123 更新时间:2023-12-03 22:21:31 25 4
gpt4 key购买 nike

我正在使用 jest+nock+jsdom 模块来测试我的 React\Redux 应用程序。
我需要测试这个异步操作功能:

export function updateUserPhoto (file, token) {
const data = new FormData()
data.append('file', file)

return dispatch => {
dispatch(userPutPhotoRequest())
return axios({
method: 'PUT',
headers: {
'x-access-token': token
},
data: data,
url: API_URL + '/user/photo'
})
.then(res => dispatch(userPutPhotoSuccess(res.data)))
.catch(err => dispatch(userPutPhotoFilure(err)))
}
}

所以我使用 jsdom 将 FormData 和 File 对象提供到测试中:
const {JSDOM} = require('jsdom')

const jsdom = (new JSDOM(''))
global.window = jsdom.window
global.document = jsdom.window.document
global.FormData = jsdom.window.FormData
const File = jsdom.window.File
global.File = jsdom.window.File

这是测试“上传照片”功能的方法:
it('creates USER_UPDATE_SUCCESS when updating user photo has been done', () => {
const store = mockStore(Map())

const file = new File([''], 'filename.txt', {
type: 'text/plain',
lastModified: new Date()
})

const expectedFormData = new FormData()
expectedFormData.append('file', file)

nock(API_URL, {
reqheaders: {
'x-access-token': token
}
}).put('/user/photo', expectedFormData)
.reply(200, {body: {}})

const expectedActions = [
{
type: ActionTypes.USER_PUT_PHOTO_REQUEST
},
{
type: ActionTypes.USER_PUT_PHOTO_SUCCESS,
response: {
body: {}
}
}
]

return store.dispatch(actions.updateUserPhoto(file, token))
.then(() => {
// return of async actions
expect(store.getActions()).toEqual(expectedActions)
})
})

我使用 nock 来模拟 axios 请求,使用 redux-mock-store 来模拟 Redux 存储。
创建 File 和 FormData 对象以将其与来自 axios 的响应进行比较。
然后我调用 Action 函数将文件和 token 作为参数传递。

在生产 Action 功能正常工作和调度 Action 成功。但在测试中我收到错误:
Error: Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream

当我在数据测试通过时传入 axios 空对象时,FormData 对象出现问题。
如何以适当的方式模拟 axios 的 FormData 对象以使该测试正常工作?

最佳答案

这个答案来得太晚了,但我想做类似的事情,我想在这里发布一个解决方案,其他人可能会偶然发现并发现有用。

这里的主要问题是 nock 模拟网络请求而不是 Javascript 库。 FormData是一个 Javascript 对象,在发出网络请求时最终会转换为文本。到了FormData对象使其成为 nock,它已被转换为 stringBuffer ,因此您看到的错误。 nock 无法使用 FormData比较的对象。

你有几个选择:

1. 最简单的解决方案

只是不要匹配 PUT 中的数据要求。您 mock 的原因是因为您不希望发出真正的 HTTP 请求,但希望返回虚假的响应。 nock只模拟一次请求,所以如果你模拟所有 PUT/user/photo 的请求nock 会捕获它,但仅用于该测试:

nock(API_URL, {
reqheaders: {
'x-access-token': token
}
}).put('/user/photo')
.reply(200, {body: {}})

在以这种方式实现测试之前,请考虑一下您的测试试图验证什么。您是否尝试验证文件是否在 HTTP 请求中发送?如果是,那么这是一个糟糕的选择。您的代码可以发送与已调度的文件完全不同的文件,但仍能通过此测试。但是,如果您有另一个测试来验证文件是否正确放入 HTTP 请求中,那么此解决方案可能会为您节省一些时间。

2. 在不匹配请求时让 nock 失败的简单解决方案

如果您的代码传递了损坏或错误的文件,您确实希望测试失败,那么最简单的解决方案是测试文件名。由于您的文件为空,因此无需匹配内容,但我们可以匹配文件名:
nock(API_URL, {
reqheaders: {
'x-access-token': token
}
}).put('/user/photo', /Content-Disposition\s*:\s*form-data\s*;\s*name="file"\s*;\s*filename="filename.txt"/i)
.reply(200, {body: {}})

这应该与您上传一个文件的简单情况相匹配。

3.匹配表单数据字段的内容

假设您有其他字段要添加到您的请求中
export function updateUserPhoto (file, tags, token) {
const data = new FormData()
data.append('file', file)
data.append('tags', tags)
...

或者您要匹配的文件中有虚假内容
const file = new File(Array.from('file contents'), 'filename.txt', {
type: 'text/plain',
lastModified: new Date()
})

这是事情变得有点复杂的地方。本质上,您需要做的是将表单数据文本解析回对象,然后编写自己的匹配逻辑。
parse-multipart-data是一个相当简单的解析器,您可以使用:

https://www.npmjs.com/package/parse-multipart-data

使用那个包你的测试可能看起来像这样
it('creates USER_UPDATE_SUCCESS when updating user photo has been done', () => {
const store = mockStore(Map())

const file = new File(Array.from('file content'), 'filename.txt', {
type: 'text/plain',
lastModified: new Date()
})

nock(API_URL, {
reqheaders: {
'x-access-token': token
}
}).put('/user/photo', function (body) { /* You cannot use a fat-arrow function since we need to access the request headers */
// Multipart Data has a 'boundary' that works as a delimiter.
// You need to extract that
const boundary = this.headers['content-disposition']
.match(/boundary="([^"]+)"/)[1];

const parts = multipart.Parse(Buffer.from(body),boundary);

// return true to indicate a match
return parts[0].filename === 'filename.txt'
&& parts[0].type === 'text/plain'
&& parts[0].data.toString('utf8') === 'file contents'
&& parts[1].name === 'tags[]'
&& parts[1].data.toString('utf8') === 'tag1'
&& parts[2].name === 'tags[]'
&& parts[2].data.toString('utf8') === 'tag2';
})
.reply(200, {body: {}})

const expectedActions = [
{
type: ActionTypes.USER_PUT_PHOTO_REQUEST
},
{
type: ActionTypes.USER_PUT_PHOTO_SUCCESS,
response: {
body: {}
}
}
]

return store.dispatch(actions.updateUserPhoto(file, ['tag1', 'tag2'], token))
.then(() => {
// return of async actions
expect(store.getActions()).toEqual(expectedActions)
})
})

关于reactjs - Redux 使用 jest、nock、axios 和 jsdom 测试 multipart/form-data,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46818751/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com