赛普拉斯在请求正文中使用文件进行HTTP POST时出错 [英] Cypress Error making HTTP POST with File in request body

查看:77
本文介绍了赛普拉斯在请求正文中使用文件进行HTTP POST时出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从赛普拉斯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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆