通过请求上传 Cypress.io 的文件

Upload File with Cypress.io via Request

给定这个简单的形式

<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 不支持本机事件(不能 select 文件),我必须使用 post-请求。

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

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

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

感谢任何建议!

bahmutov's cypress-form-data-with-file-upload makes reference to the github issues (311 and 170) 正在考虑这个问题,并为那些不能适应赛普拉斯在这方面的限制的人提供了一个相当肮脏的解决方法。

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

Cypress.Commands.add("xhr", (method, url, formdata) => {
    // inspired by https://github.com/bahmutov/cypress-form-data-with-file-upload/blob/8fe6106d28eef0634c78564c746746d1cc354e99/index.js
    // fixes lack of FormData (multipart/form-data) support in cy.request
    cy.window()
    .then(win => {
        return new Promise((resolve, reject) => {
            const XHR = new win.XMLHttpRequest()
            XHR.onload = resolve
            XHR.open(method, url)
            XHR.send(formdata)
        })
    })
})

并附上Blobs or Files as needed to an instance of FormData.

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

如果它对某人有帮助,我会把它留在这里 https://github.com/javieraviles/cypress-upload-file-post-form

第二种情况(send_form_data_with_file_in_post_request_spec.js):

I want to build up the FormData myself( new FormData(), formData.append/formData.set ) and send it directly with a POST request to the backend or submit the form with the FormData I have created. For this case, the transmitted data must be in the same format as the form's submit(), which type is set to "multipart/form-data". Having a look at the MDN web docs to see how you can build a FormData: Using FormData Objects, and knowing that at this very moment (Cypress 2.1.0) cy.request doesn't support FormData (multipart/form-data) so we will need a XMLHttpRequest, the test can be performed as follows. Include the following code in your "commands.js" file within the cypress support folder, so the command cy.form_request() can be used from any test:
// 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);
            });

        })

    })

})

})

我今天 运行 研究了这个问题并开发了一个与其他答案类似的解决方案,但它允许您使用 .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
  });

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

请注意,更多的只是上传文件,而不是专门针对表单。

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

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

以下在我的案例中工作得很好:

cy.fixture('something.svg').then((file) => {
  cy.request({
    url: 'http://mock/uploads/some-id',
    method: 'put',
    body: file,
  });
});

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

我无法让 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 文件 - 无论你做什么,都必须使用在线转换器或 base64 命令以 base64 编码Linux.

出于测试目的,请确保它包含文本 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
            });
        });
    });
});