0

Cypress: Intercepting a binary file download call -> corruped Zip

Hello there. I want to intercept a binary file download api call using cypress. I want to mock it with a local file. It is a zip file. The backend sends me a binary.

The requests:
Body response The Content-Type is application/octet-stream

Real world response header:
Access-Control-Allow-Credentials:
true
Access-Control-Expose-Headers:
Content-Disposition
Content-Type:
application/octet-stream
Date:
Mon, 22 May 2023 12:06:47 GMT

Real world request header:
Accept:
application/octet-stream

Mocked with cypress response header:
access-control-allow-credentials: true
access-control-allow-origin: *
Connection: keep-alive
Content-Type: octet-stream
Date: Mon, 22 May 2023 11:54:56 GMT
Keep-Alive: timeout=5
Transfer-Encoding: chunked

Mocked with cypress request header:
GET /backup HTTP/1.1
Accept: application/octet-stream
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Referer: http://127.0.0.1:4200/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/111.0.0.0 Safari/537.36
X-Cypress-Is-XHR-Or-Fetch: xhr
sec-ch-ua: "Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"

In my applications it becomes a Blob and I can unzip it and work with the content. If I take the same file and use cypress' readFile I see the exact same string as the above body response. I put it in the interceps body. I also set the proper headers.

The error: "Error: Corrupted zip: missing 2059592310 bytes." occurs The logged Blob also has a different size, even tho it is the same file.

real world: »Blob {size: 31478, type: 'application/octet-stream'}
mocked with cypress: »Blob {size: 56721, type: 'application/octet-stream'}

Code:

Then('I navigate to the live settings tab and intercept the download call', () => {
cy.readFile('src/fixtures/machines/machine-settings-export/settings_values.zip', 'utf-8').then((file) => {
    cy.intercept('GET', '**/backup', (req) => {
        // reset the request header in case it does make any difference
        req.headers['accept-encoding'] = null;
        
        // file and headers are set
        console.warn('headers', req.headers);
        console.warn('file', file);

        req.reply({
            statusCode: 200,
            body: file,
            headers: {
                'Content-Type': 'octet-stream',
            },
        });
    }).as('downloadCall');

    cy.get('machine-configurations-dialog').contains('LIVE MASCHINEN-EINSTELLUNGEN').click();
});
cy.wait('@downloadCall')
    .its('request')
    .then((req) => {
        // body is empty for some reason aswell
        console.warn('download intercept its request: ', req);
        
        // download it here aswell to test it in another way
        const fileName = `1234TEST.zip`;
        saveAs(req.body, fileName);
    });

});

What I tried:
I tried to remove the accept-encoding header. I thought the browser might handle the response in a different way, but it didnt work out.

I also tried using different encodings for the readFile (utf8 or binary) but utf8 seems right because the response body looks identical to the real world applications.

I found some github issues where people also had problems with intercepting binary files. https://github.com/cypress-io/cypress/issues/16722
https://github.com/cypress-io/cypress/issues/15038

I really dont know what it could be.

Since in the real world application and in the intercepted cypress call the response body was identical (the picture) I think the problem may be the intercept itself or different headers.

I also tried setting the response headers
'Accept-Ranges': 'bytes',
'Content-Length': file.length.toString(),

This resulted in a different length of the Blob and another error:
Blob {size: 30009, type: 'application/octet-stream'}
Corrupted zip: can't find end of central directory

Update:

Setting readfile to 'binary' seems right. Using this code afterwards works perfectly and lets me unpack the zip:

cy.writeFile('cypress/fixtures/machines/machine-settings-export/test.zip', file, 'binary');

file.length is the correct number. After the blob creating inside the api service the the size of the blob is almost twice as big. I have no idea why this happens. This only happens whenever I dont set the content-length header. If I do set the header, the blob size will be correct, but it is still a corrupted zip. The content-type header does not make any difference to that behavior.
log screenshot original file size

Paul
  • 1
  • 3

1 Answers1

0

Solution:

cy.intercept('**/backup', {fixture: 'machines/machine-settings-export/settings_values.zip', statusCode: 200}).as('downloadCall');

The most obvious solutions was to just use a fixture.

Paul
  • 1
  • 3