8

鉴于这种简单的形式

<form action="/upload_file" method="POST" enctype="multipart/form-data" id="upload_file_form">
    <input type="file" name="file" required>
    <input type="text" placeholder="Select file" disabled>
    <input type="submit" value="upload">
</form>

由于 cypress.io 不支持本机事件(无法选择文件),我必须使用后请求。

cypress.io 中的请求结构看起来像

cy.request({
    method: 'POST',
    url: '/some/url',
    form: true,
    body: { ... },
    headers:{ ... }
})

我想知道如何发送一个简单的 *.txt

任何建议表示赞赏!

4

6 回答 6

7

将其留在这里以防它帮助某人 https://github.com/javieraviles/cypress-upload-file-post-form

第二种情况(send_form_data_with_file_in_post_request_spec.js):

我想自己构建 FormData( new FormData(), formData.append/formData.set )并通过 POST 请求直接将其发送到后端,或者使用我创建的 FormData 提交表单。对于这种情况,传输的数据必须与表单的 submit() 格式相同,类型设置为“multipart/form-data”。查看 MDN Web 文档以了解如何构建 FormData:使用 FormData 对象,并且知道此时(赛普拉斯 2.1.0)cy.request 不支持 FormData(multipart/form-data)所以我们需要一个 XMLHttpRequest,测试可以如下进行。在 cypress 支持文件夹中的“commands.js”文件中包含以下代码,因此可以在任何测试中使用命令 cy.form_request():
// Performs an XMLHttpRequest instead of a cy.request (able to send data as 
// FormData - multipart/form-data)
Cypress.Commands.add('form_request', (method, url, formData, done) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function () {
        done(xhr);
    };
    xhr.onerror = function () {
        done(xhr);
    };
    xhr.send(formData);
})

然后,如果您想发送与以前相同的表单(包含 excel 文件和其他普通输入的表单)但自己构建并直接发送到服务器,测试将是这样的:

describe('Testing the API', function () {

    it('Receives valid FormData and proccesses the information correctly', 
        function () {

    /*
    The reason why this test may look a bit tricky is because the backend endpoint is expecting the 
    submission of a web Form (multipart/form-data), not just data within a POST. The "cy.request()" 
    command doesn't support sending a web Form as a body in a POST request, so the test uses a support 
    command that has been created to perform a genuine XMLHttpRequest where a web Form can be placed.
    */

    //Declarations
    const fileName = 'your_excel_file.xlsx';
    const method = 'POST';
    const url = 'http://localhost:3000/api/excel_form';
    const fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
    const inputContent2 = 'input_content2';
    const expectedAnswer = '{"msg":"X elements from the excel where successfully imported"}';

    // Get file from fixtures as binary
    cy.fixture(fileName, 'binary').then( (excelBin) => {

        // File in binary format gets converted to blob so it can be sent as Form data
        Cypress.Blob.binaryStringToBlob(excelBin, fileType).then((blob) => {

            // Build up the form
            const formData = new FormData();
            formData.set('file', blob, fileName); //adding a file to the form
            formData.set('input2', inputContent2); //adding a plain input to the form
            .
            .
            .
            // Perform the request
            cy.form_request(method, url, formData, function (response) {
                expect(response.status).to.eq(200);
                expect(expectedAnswer).to.eq(response.response);
            });

        })

    })

})

})

于 2018-05-14T20:32:22.157 回答
2

我只需要从赛普拉斯上下文中将文件上传到某处(在浏览器请求之前模拟某些内容)。

在我的情况下,以下工作正常:

cy.fixture('something.svg').then((file) => {
  cy.request({
    url: 'http://mock/uploads/some-id',
    method: 'put',
    body: file,
  });
});
于 2020-07-02T10:13:27.227 回答
1

bahmutov 的 cypress-form-data-with-file-upload参考了正在考虑这个问题的 github 问题(311170),并为那些无法适应赛普拉斯在这方面的限制的人提供了一个相当肮脏的解决方法。

解决方法是创建一个自定义XHR对象并使用它来提交附加文件的请求,而不是 Cypress' cy.request。提供的解决方法仅限于使用<input type="file" />元素的值。在我的情况下,我需要在我的请求中使用一个夹具,所以我的解决方案是创建一个自定义 cypress 命令

Cypress.Commands.add("xhr", (method, url, formdata) => {
    // 灵感来自 https://github.com/bahmutov/cypress-form-data-with-file-upload/blob/8fe6106d28eef0634c78564c746746d1cc354e99/index.js
    // 修复 cy.request 中缺少 FormData (multipart/form-data) 支持
    cy.window()
    .then(赢=> {
        返回新的承诺((解决,拒绝)=> {
            const XHR = new win.XMLHttpRequest()
            XHR.onload = 解决
            XHR.open(方法,网址)
            XHR.send(formdata)
        })
    })
})

并根据需要将Blob文件附加到FormData的实例。

我强烈建议使用 Cypress,例如,如果可以的话,接受 base64 编码的文件数据作为纯文本,因为与此解决方法相关的复杂性。

于 2018-05-04T10:38:39.477 回答
1

我今天遇到了这个问题,并开发了与其他答案类似的解决方案,但它允许您使用.then()赛普拉斯语法。

将此添加到 support/commands.js:

Cypress.Commands.add("form_request", (url, formData) => {
  return cy
    .server()
    .route("POST", url)
    .as("formRequest")
    .window()
    .then(win => {
      var xhr = new win.XMLHttpRequest();
      xhr.open(method, url);
      xhr.send(formData);
    })
    .wait("@formRequest");
  });

然后您就可以在测试中执行以下操作:

cy
  .form_request(url, formData)
  .then(response => {
    // do stuff with your response
  });
于 2018-07-25T18:40:28.317 回答
0

我周末大部分时间都花在这上面,所以会发布适合我的解决方案。

我无法让 NPM 包中的示例按照cypress-upload-file-post-form编写的方式工作。具体来说,我在Cypress.Blob.binaryStringToBlob.

第1步

support/commands.js添加此功能

Cypress.Commands.add('multipartFormRequest', (method, url, formData, done) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function () {
        done(xhr);
    };
    xhr.onerror = function () {
        done(xhr);
    };
    xhr.send(formData);
});

第2步

将一个名为的文件添加Base64TestCV.rtf到该fixtures文件夹​​。

我想要一个.rtf文件,但显然你可以制作一个.txt文件——无论你做什么,都必须使用在线转换器或base64Linux 中的命令以 base64 编码。

出于测试目的,请确保它包含文本MyCypressTestCV(显然以 base64 编码)。

第 3 步

创建并运行您的测试。在这个例子中,我的.rtf文件包含MyCypressTestCV由 httpbin.org 反射回来的文本,因此它证明它是从 base64 正确解码并上传的。

describe('Upload a file to a multipart form using cy.request', function () {
    it('Performs a multipart post to httpbin.org', function () {
        const baseUrl = 'http://httpbin.org';
        const postUrl = `${baseUrl}/post`;

        cy.visit(baseUrl); // Cypress will be very buggy if you don't do at least one cy.visit

        cy.request(baseUrl).as('multipartForm'); // pretend we are doing the GET request for the multipart form

        const base64FileName = 'Base64TestCV.rtf';
        const postedFileName = 'TestCV.rtf';
        const method = 'POST';
        const mimeType = 'application/rtf';

        cy.fixture(base64FileName).as('base64File'); // file content in base64

        cy.get('@multipartForm').then((response) => {
            const formData = new FormData();
            formData.append('firstFormField', 'Hello');
            formData.append('secondFormField', '25');
            const blob = Cypress.Blob.base64StringToBlob(this.base64File, mimeType);
            formData.append('uploadFile', blob, postedFileName);

            cy.multipartFormRequest(method, postUrl, formData, function (response) {
                expect(response.status).to.eq(200);
                expect(response.response).to.match(/MyCypressTestCV/); // http://httpbin.org/post reflects what you post
            });
        });
    });
});
于 2021-02-21T14:37:13.377 回答
-3

在等待内置支持的同时,我们可以停止复制粘贴 hack 并从中创建一个可重用的包。随意打开问题,以便我们可以使其适用于最流行的用例。

请注意,这不仅仅是上传文件,而不是专门关注表单。

https://www.npmjs.com/package/cypress-file-upload

于 2019-01-31T08:51:38.273 回答