赛普拉斯在请求正文中使用文件进行HTTP POST时出错 [英] Cypress Error making HTTP POST with File in request body
问题描述
我从赛普拉斯6.8.0升级到了7.0.1.升级后,当赛普拉斯测试之一调用此功能时
async saveTask(任务,文件){const requestBody = new FormData()requestBody.append('file',file)返回等待http.post('/api/endpoint',requestBody,{标头:{内容类型":多部分/表单数据"}})},
我收到以下错误
TypeError [ERR_INVALID_ARG_TYPE] [ERR_INVALID_ARG_TYPE]:第一个参数必须是字符串类型,或者是Buffer或Uint8Array的实例.收到的类型编号(45)在write_(_http_outgoing.js:696:11)在ClientRequest.write(_http_outgoing.js:661:15)在Request.write(/Users/donal/Library/Caches/Cypress/7.0.1/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/request/request.js:1496:27)在/Users/donal/Library/Caches/Cypress/7.0.1/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/request/request.js:546:20中在Array.forEach(< anonymous>:null:null)最后(/Users/donal/Library/Caches/Cypress/7.0.1/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/request/request.js:545:23)立即发布(_Users/donal/Library/Caches/Cypress/7.0.1/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/request/request.js:578:7).在processImmediate(internal/timers.js:461:21){代码:"ERR_INVALID_ARG_TYPE"}
我用来发出POST请求的 http
对象是Axios实例,我附加到请求正文的 file
对象是 Axios请求配置文档表示当Axios在Node下运行时,文件
是不允许的.
//`data`是要作为请求正文发送的数据//仅适用于请求方法'PUT','POST','DELETE和'PATCH'//如果未设置`transformRequest`,则必须为以下类型之一://-字符串,普通对象,ArrayBuffer,ArrayBufferView,URLSearchParams//-仅限浏览器:FormData,文件,Blob//-仅节点:流,缓冲区数据: {firstName:"Fred"},
所以我想我需要将 File
对象转换为其他,以便该功能既可以在应用程序内部运行,也可以在Cypress运行时起作用./p>
在服务器端(Spring Boot应用程序),此文件绑定到 MultipartFile
public void handlePost(RequestPart(值=文件")MultipartFile文件){//控制器动作主体}
如果我的理论认为 File
类型是问题,那么我应该使用什么代替,以及如何进行转换?
仅当该功能通过赛普拉斯测试运行时才会发生错误.赛普拉斯使用Node.js,并根据上面的错误消息进行判断不允许使用文件类型.此外,Axios请求配置docs指出,当Axios在Node下运行时,不允许使用文件.
默认情况下, Cypress
以无头模式启动 Electron
,即测试始终可以访问浏览器API.您可以控制要在哪个浏览器上运行测试.此处.
现在让我们看看文件上传的解决方案
假设您在函数 saveTask
中引用的 file
是 type = file
的 input
字段,并且 name = file
.
比方说,您需要上传一个名为 email.png
的png图像,该图像位于 cypress/fixtures/images/email.png
.
使用以下代码块上传文件.
cy.fixture('images/email.png').as('emailImage')cy.get('input [name = file]').then(function(el){const blob = Cypress.Blob.base64StringToBlob(this.emailImage,'image/png')const file = new File([blob],'email.png',{type:'image/png'})const list = new DataTransfer()list.items.add(文件)el [0] .files = list.filesel [0] .dispatchEvent(new Event('change',{bubble:true}))})
现在,您可以触发调用上传api(/api/endpoint)的操作,并最终确认上传成功.
//触发导致上载api被调用的操作,例如点击一个按钮cy.get('input [type = button]').click();//验证api调用是否成功(以下代码检查id为result的div是否具有字符串'Success')cy.get('#result').should('contain','Success');
您可以上传任何类型的文件,而不必是图像.有关更多信息,请参见夹具和示例关于Blob文档.
I upgraded from Cypress 6.8.0 to 7.0.1. After the upgrade, when this function is called by one of the Cypress tests
async saveTask (task, file) {
const requestBody = new FormData()
requestBody.append('file', file)
return await http.post('/api/endpoint', requestBody, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
},
I get the following error
TypeError [ERR_INVALID_ARG_TYPE] [ERR_INVALID_ARG_TYPE]:
The first argument must be of type string or an instance of Buffer or Uint8Array. Received type number (45)
at write_ (_http_outgoing.js:696:11)
at ClientRequest.write (_http_outgoing.js:661:15)
at Request.write (/Users/donal/Library/Caches/Cypress/7.0.1/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/request/request.js:1496:27)
at /Users/donal/Library/Caches/Cypress/7.0.1/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/request/request.js:546:20
at Array.forEach (<anonymous>:null:null)
at end (/Users/donal/Library/Caches/Cypress/7.0.1/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/request/request.js:545:23)
at Immediate._onImmediate (/Users/donal/Library/Caches/Cypress/7.0.1/Cypress.app/Contents/Resources/app/packages/server/node_modules/@cypress/request/request.js:578:7)
at processImmediate (internal/timers.js:461:21)
{
code: 'ERR_INVALID_ARG_TYPE'
}
The http
object that I use to make the POST request is an Axios instance and the file
object that I append to the request body is a File. The file object is the cause of the problem, because if I don't append it to the request body, the error doesn't occur.
The error only occurs when the function is run by a Cypress test. Cypress uses Node.js, and judging by the error message above it seems the File
type is not allowed. Furthermore, the Axios request config docs indicate that when Axios runs under Node, a File
is not allowed.
// `data` is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', 'DELETE , and 'PATCH'
// When no `transformRequest` is set, must be of one of the following types:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - Browser only: FormData, File, Blob
// - Node only: Stream, Buffer
data: {
firstName: 'Fred'
},
So I guess I need to convert the File
objects to something else, so that this function will work both within the app itself, and when run by Cypress.
On the server-side (a Spring Boot app), this file is bound to a MultipartFile
public void handlePost(
RequestPart(value = "file") MultipartFile file) {
// controller action body
}
If my theory that the File
type is the problem, what should I use instead and how should I do the conversion?
The error only occurs when the function is run by a Cypress test. Cypress uses Node.js, and judging by the error message above it seems the File type is not allowed. Furthermore, the Axios request config docs indicate that when Axios runs under Node, a File is not allowed.
By default Cypress
starts Electron
in headless mode, i.e. the tests would always have access to browser APIs. You can control on which browser you want to run the tests. More details here.
Now let's look at the solution for file upload
Assuming the file
you are referring in the function saveTask
is an input
field of type=file
and name=file
.
And let's say, you need to upload a png image named email.png
which is at cypress/fixtures/images/email.png
.
Use the following block of code for uploading the file.
cy.fixture('images/email.png').as('emailImage')
cy.get('input[name=file]').then(function (el) {
const blob = Cypress.Blob.base64StringToBlob(this.emailImage, 'image/png')
const file = new File([blob], 'email.png', { type: 'image/png' })
const list = new DataTransfer()
list.items.add(file)
el[0].files = list.files
el[0].dispatchEvent(new Event('change', { bubbles: true }))
})
Now you can trigger the action based on which your upload api (/api/endpoint) is invoked and finally verify the upload is successful.
// Trigger the action which causes the upload api to be invoked e.g. clicking on a button
cy.get('input[type=button]').click();
// Verify the api invocation is successful (The below code checks a div with id result to have the String 'Success')
cy.get('#result').should('contain', 'Success');
You can upload any type of file and it doesn't have to be an image. For more information look at fixture and Blob. This answer is based on this example on Blob documentation.
这篇关于赛普拉斯在请求正文中使用文件进行HTTP POST时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!