Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can cy.writeFile write any type of document? #2029

Closed
kutlaykural opened this issue Jun 25, 2018 · 15 comments · Fixed by #7382
Closed

can cy.writeFile write any type of document? #2029

kutlaykural opened this issue Jun 25, 2018 · 15 comments · Fixed by #7382
Labels
type: feature New feature that does not currently exist

Comments

@kutlaykural
Copy link

kutlaykural commented Jun 25, 2018

Current behavior:

After a download attempt an excel file with cy.request() command, response.body can be saved by using cy.writeFile command with any filename and extension (like 'text.xlsx') but file cannot be open.

Desired behavior:

Any type of file should be saved with any extension and can be opened properly.

Versions

Cypress: 3.0.1
Operating system: Mac
Browser : Electron 59

@brian-mann
Copy link
Member

To better understand this use case, why do you need to cy.writeFile a response you got from your server? Couldn't you do assertions directly on the response.body?

For instance, if you could write a giant .csv or .xslx or .pdf what more would you do inside of Cypress past that point?

I'm just trying to understand what you actually gain by writing the file after you receive the response.

What is the content type of the server's response? My guess is that you need to set the encoding correctly in fs.writeFile and then it will be opened correctly.

@brian-mann brian-mann added the stage: needs information Not enough info to reproduce the issue label Jun 25, 2018
@kutlaykural
Copy link
Author

kutlaykural commented Jun 26, 2018

After download this file i need to insert some data and upload it back to server.
Here is the response:

screen shot 2018-06-25 at 18 43 08

I tried all of supported encoding types of cy.writefile but none of them worked for me.

@jennifer-shehane
Copy link
Member

Do you need it in .xlsx format in order to upload it to the server? Or did you want it in .xlsx format in order to update the data from that filetype?

@brian-mann
Copy link
Member

@kutlaykural can you provide your code? The screenshot you posted is just headers, not the body.

@kutlaykural
Copy link
Author

kutlaykural commented Jun 27, 2018

@jennifer-shehane
Server provide me data only in excel format. And server accept data to upload in this format too.

@brian-mann
(to gather a download link i also do some other request)
here is test file code:

var downloadUrl='/v1/enterprise/import/template/'+jobId;
cy.request({
    method: 'GET',
    url: downloadUrl 
}).then((response) => { 
    cy.writeFile('/cypress/fixtures/excel.xlsx',response.body) 
}) 

@jennifer-shehane jennifer-shehane added stage: investigating Someone from Cypress is looking into this type: feature New feature that does not currently exist and removed stage: needs information Not enough info to reproduce the issue labels Jul 12, 2018
@miketeo
Copy link

miketeo commented Aug 2, 2018

I am having a similar issue here, except that I am dealing with zip files.

cy.log('Package URL is ' + downloadURL)
cy.request(downloadURL).then((response) => {
    expect(response.status).to.be.equal(200)
     cy.log(response.body.length)
     cy.writeFile('cypress/work/downloadTest.zip', response.body, 'binary')
})

The logged response.body.length (50505) is of different value from the original file size on the server and the content-length header (53398) in the response. If I manually download the zip file using another web browser, the saved file can be opened correctly.

I suspect cy.request is performing some post-processing on the response body, even though the response's content-type is set to application/zip. I have repeated the same test a number of times; the response.body.length is always the same length, so it is clearly not a network issue.

console screenshot

@andrewleith
Copy link

Same issue here, the downloaded zip is corrupt.

@jennifer-shehane jennifer-shehane added stage: ready for work The issue is reproducible and in scope and removed stage: investigating Someone from Cypress is looking into this labels Oct 20, 2018
@nootn
Copy link

nootn commented Dec 6, 2018

Yes I have come across this issue too. I am thinking of maybe using cypress to get the URL, but maybe using something else to hit that URL to download the file as a workaround for now.

@Prashant-Kan
Copy link

@nootn : Did you find any workaround for this?
Me also come across similar issue.
I want to assert the download file data. I got the way to parse the pdf but the pdf should be in the fixture or plugin folder. For that I need to write the repoinse that I got from the server.

@roma-glushko
Copy link

roma-glushko commented Feb 24, 2019

Got the same issue on downloading/saving PDF files. Can anyone help us with this?

@jennifer-shehane jennifer-shehane changed the title can cy.writeFile can write any type of document? can cy.writeFile write any type of document? Feb 25, 2019
@WesleySSmith
Copy link

WesleySSmith commented Mar 3, 2019

As a workaround, I found that I could use a custom plugin to perform the download. In my case, I was trying to download an xlsx file, but I think a similar approach could be used to test PDF files or just save the files after downloading them.

Added via npm:

  • node-xlsx (specific to xlsx parsing)
  • request (to make https request)

plugins/index.js:

on('task', {
    // args must be {url: "<url>, cookies: [{name: "cookie1", value: "value1"}, {name: "cookie2", value: "value2"}, ...]"}
    parseXlsx(args) {
      const cookieheader = args.cookies.map(e => e.name + "=" + e.value).join(";");
      return new Promise((resolve, reject) => {
        const r = request({url: args.url, encoding:null, headers: {Cookie: cookieheader}}, function(err, res, body) {
          if (!res) {
            return reject(new Error("No response"));
          }
          if (res.statusCode !== 200) {
            return reject(new Error("Bad status code: " + res.statusCode));
          }
          const sheet = xlsx.parse(body);
          console.log(JSON.stringify(sheet));
          resolve(sheet);
        });
      });
    }
  });

support/commands.js:

Cypress.Commands.add("parseXlsx", (url) => {
    return cy.getCookies().then(cookies => {
        return cy.task('parseXlsx', {url: url, cookies: cookies });
    });
});

In my test file:

// Call parseXlsx and verify that the export is as expected
  cy.parseXlsx(exportUrl).should(data => {
          expect(data).to.have.xlsSheetName("Payments");
          expect(data).to.have.xlsSheetRowCell(0,0,0,'Reference #');
      });

@roma-glushko
Copy link

roma-glushko commented Mar 3, 2019

@WesleySSmith thank you very much, this idea helped me to create a workaround. Maybe I put it here, just in a case someone needs it, too:

plugins/index.js:

const request = require('request');
const fs = require('fs');

module.exports = (on, config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config

    on('task', {
        downloadPdf(args) {
            const directory = args.directory;
            const cookieHeader = args.cookies.map(e => e.name + '=' + e.value).join(';');

            return new Promise((resolve, reject) => {
                request({url: args.url, encoding: null, headers: {Cookie: cookieHeader}}, function(err, res, body) {
                    if (!res) {
                        return reject(new Error('No response'));
                    }

                    if (res.statusCode !== 200) {
                        return reject(new Error('Bad status code: ' + res.statusCode));
                    }

                    const contentDisposition = res.headers['content-disposition'];

                    if (!contentDisposition || contentDisposition.indexOf('inline') === -1) {
                        return reject(
                            new Error('Broken response: does not contain content-disposition of inline file type')
                        );
                    }

                    const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                    const matches = filenameRegex.exec(contentDisposition);

                    if (matches == null || !matches[1]) {
                        return reject(new Error('Broken response: does not contain filename'));
                    }

                    const fileName = matches[1].replace(/['"]/g, '') + '.pdf';

                    fs.writeFileSync(directory + fileName, body);
                    resolve(body);
                });
            });

        }
    });

};

support/commands.js:

Cypress.Commands.add('downloadPdf', (url, directory) => {
    return cy.getCookies().then(cookies => {
        return cy.task('downloadPdf', {url: url, directory: directory, cookies: cookies });
    });
});

In my test file:

cy.downloadPdf(pdfUrl, 'temp/');

My plugin/index.js contains a bit more code, because I need to parse response headers in order to get correct PDF filename.

Also, I reported this issue in a separated task: #3576
So it's already approved and marked as a bug and hopefully we won't need to use such workarounds soon 🙌

@turulb
Copy link

turulb commented Mar 28, 2019

Thanks roma-glushko! Saved my day.

@cypress-bot cypress-bot bot added stage: work in progress There is an open PR for this issue [WIP] stage: needs review The PR code is done & tested, needs review and removed stage: ready for work The issue is reproducible and in scope stage: work in progress There is an open PR for this issue [WIP] labels May 18, 2020
@cypress-bot cypress-bot bot removed the stage: needs review The PR code is done & tested, needs review label May 26, 2020
@cypress-bot
Copy link
Contributor

cypress-bot bot commented May 26, 2020

The code for this is done in cypress-io/cypress#7382, but has yet to be released.
We'll update this issue and reference the changelog when it's released.

@cypress-bot
Copy link
Contributor

cypress-bot bot commented May 26, 2020

Released in 4.7.0.

This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v4.7.0, please open a new issue.

@cypress-bot cypress-bot bot locked as resolved and limited conversation to collaborators May 26, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type: feature New feature that does not currently exist
Projects
None yet
10 participants