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

时间:2017-11-28 14:28:30

标签: javascript post cypress

鉴于这种简单的形式

Process.Start()

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

cypress.io中的请求结构类似于

<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>

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

任何建议都赞赏!

6 个答案:

答案 0 :(得分:3)

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

第二种情况(send_form_data_with_file_in_post_request_spec.js):

    我想自己构建FormData(新的FormData(),formData.append / formData.set)并直接将POST请求发送到后端,或者使用我创建的FormData提交表单。 对于这种情况,传输的数据必须与表单的submit()格式相同,该类型设置为&#34; multipart / form-data&#34;。看看MDN Web文档,了解如何构建FormData:使用FormData Objects,并且知道此时(赛普拉斯2.1.0)cy.request不支持FormData(multipart / form-data) )所以我们需要一个XMLHttpRequest,测试可以按如下方式执行。 在&#34; commands.js&#34;中包含以下代码cypress支持文件夹中的文件,因此命令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);
            });

        })

    })

})

})

答案 1 :(得分:1)

我只是需要从Cypress上下文中上传文件到某个地方(在浏览器请求文件之前模拟一下)。

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

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

答案 2 :(得分:0)

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

解决方法是创建自定义XHR对象,并使用该对象提交附加文件的请求,而不是赛普拉斯cy.request。提供的解决方法仅限于使用<input type="file" />元素的值。在我的情况下,我需要在我的请求中使用一个fixture,所以我的解决方案是创建一个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)
        })
    })
})

根据需要将BlobsFiles附加到FormData的实例。

我强烈建议您接受赛普拉斯,例如,接受base64编码的文件数据作为纯文本,如果可以的话,由于与此变通办法相关的复杂性。

答案 3 :(得分:0)

我今天遇到了这个问题,并针对其他答案开发了类似的解决方案,但是它允许您使用.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
  });

答案 4 :(得分: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 文件 - 无论你做什么,都必须使用在线转换器或 Linux 中的 base64 命令以 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
            });
        });
    });
});

答案 5 :(得分:-1)

在等待内置支持时,我们可以停止复制粘贴该hack,并从中创建可重用的程序包。 随时公开问题,以便我们使其适合最流行的用例。

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

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