Giter VIP home page Giter VIP logo

Comments (8)

HarshRohila avatar HarshRohila commented on July 18, 2024 2

I was facing this issue when using mirage js with pdf js
I found where pretender storing original fetch, so created a workaround function

export default async function useNativeFetch(anyFunc) {
	const savedFetch = window.fetch;
	window.fetch = mirageServer.pretender._nativefetch;

	const res = await anyFunc();

	window.fetch = savedFetch;
	return res;
}

using it like this

const pdf = await useNativeFetch(
	() => pdfjsLib.getDocument(pdfUrl).promise
);

from pretender.

mydea avatar mydea commented on July 18, 2024 1

No, sadly not!

from pretender.

janmisek avatar janmisek commented on July 18, 2024

This is kind blocking. Without pretender fetch('/image.png') returns corrent blob with correct size. With pretender it does not.

from pretender.

ankology avatar ankology commented on July 18, 2024

Any solution found @mydea ? I made a entire app with pretender and found that issue too..

from pretender.

ankology avatar ankology commented on July 18, 2024

I started to look at pretender source code and have found a solution. In create-passthrough.ts#L28 just check blob and arraybuffer response types, this solves the main issue with blob's. I found another issues, some events are firing twice and when using axios the event "readystatechange" are not firing properly depending on implementation. So, basically needs to replace the createPassthrough function from the file create-passthrough.ts with the changes (Changes explained prefixed by ### in comments):

function createPassthrough(fakeXHR, nativeXMLHttpRequest) {
   // event types to handle on the xhr
   var evts = ['error', 'timeout', 'abort', 'readystatechange'];
   // event types to handle on the xhr.upload
   var uploadEvents = [];
   // properties to copy from the native xhr to fake xhr
   var lifecycleProps = [
       'readyState',
       'responseText',
       'response',
       'responseXML',
       'responseURL',
       'status',
       'statusText',
   ];
   var xhr = (fakeXHR._passthroughRequest = new nativeXMLHttpRequest());
   xhr.open(fakeXHR.method, fakeXHR.url, fakeXHR.async, fakeXHR.username, fakeXHR.password);
   // if (fakeXHR.responseType === 'arraybuffer') {
   //### check for blob either
   if (~['blob', 'arraybuffer'].indexOf(fakeXHR.responseType)) {
       lifecycleProps = ['readyState', 'response', 'status', 'statusText'];
       xhr.responseType = fakeXHR.responseType;
   }
   // use onload if the browser supports it
   if ('onload' in xhr) {
       evts.push('load');
   }

   // add progress event for async calls
   // avoid using progress events for sync calls, they will hang https://bugs.webkit.org/show_bug.cgi?id=40996.
   // if (fakeXHR.async && fakeXHR.responseType !== 'arraybuffer') {
   //### just check for async request
   if (fakeXHR.async) {
       evts.push('progress');
       uploadEvents.push('progress');
   }
   // update `propertyNames` properties from `fromXHR` to `toXHR`
   function copyLifecycleProperties(propertyNames, fromXHR, toXHR) {
       for (var i = 0; i < propertyNames.length; i++) {
           var prop = propertyNames[i];
           if (prop in fromXHR) {
               toXHR[prop] = fromXHR[prop];
           }
       }
   }
   // fire fake event on `eventable`
   function dispatchEvent(fakeXHR, eventType, event) {

     //### only dispatchEvent, not manual firing events
     fakeXHR.dispatchEvent(event);

     // if (fakeXHR['on' + eventType]) {
     //
     //   // fakeXHR['on' + eventType](event);
     // }
   }

   // set the on- handler on the native xhr for the given eventType
   function createHandler(eventType) {

       //### delete manual addition of events and re-adding the listener to dispatchEvent always work properly
       const fakeEventKey = 'on'+eventType;

       if(fakeXHR[fakeEventKey]){

         const fn = fakeXHR[fakeEventKey];
         delete fakeXHR[fakeEventKey];

         fakeXHR.addEventListener(eventType, fn);
       }

       xhr.addEventListener(eventType, function (event) {
         copyLifecycleProperties(lifecycleProps, xhr, fakeXHR);
         dispatchEvent(fakeXHR, eventType, event);
       });
       //###

       // xhr['on' + eventType] = function (event) {
       //     copyLifecycleProperties(lifecycleProps, xhr, fakeXHR);
       //     dispatchEvent(fakeXHR, eventType, event);
       // };
   }
   // set the on- handler on the native xhr's `upload` property for
   // the given eventType

   function createUploadHandler(eventType) {

     // if (xhr.upload && fakeXHR.upload && fakeXHR.upload['on' + eventType]) {
     if (xhr.upload && fakeXHR.upload) {

       //### delete manual addition of events and re-adding the listener to dispatchEvent always work properly
       const fakeEventKey = 'on'+eventType;

       if(fakeXHR.upload[fakeEventKey]){

         const fn = fakeXHR.upload[fakeEventKey];
         delete fakeXHR.upload[fakeEventKey];

         fakeXHR.upload.addEventListener(eventType, fn);
       }

       xhr.upload.addEventListener(eventType, function (event) {
         dispatchEvent(fakeXHR.upload, eventType, event);
       });
       //###

       // xhr.upload['on' + eventType] = function (event) {
       //     dispatchEvent(fakeXHR.upload, eventType, event);
       // };
       }
   }
   var i;
   for (i = 0; i < evts.length; i++) {
       createHandler(evts[i]);
   }
   for (i = 0; i < uploadEvents.length; i++) {
       createUploadHandler(uploadEvents[i]);
   }
   if (fakeXHR.async) {
       xhr.timeout = fakeXHR.timeout;
       xhr.withCredentials = fakeXHR.withCredentials;
   }
   for (var h in fakeXHR.requestHeaders) {
       xhr.setRequestHeader(h, fakeXHR.requestHeaders[h]);
   }
   return xhr;
}

And my tests code:

import axios from 'axios';
import Pretender from 'pretender';

const server = new Pretender(function() {

    this.get('/test', () => {

        return [200, {}, {data: {foo: 'bar'}}]
    });
});

server.unhandledRequest = function(verb, path, request) {

    const xhr = request.passthrough();

    xhr.onloadend = (ev) => {
        console.warn(`Response for ${path}`, {
            verb,
            path,
            request,
            responseEvent: ev,
        })
    };
};

const urls = [

    'https://static.vecteezy.com/system/resources/thumbnails/000/246/312/original/mountain-lake-sunset-landscape-first-person-view.jpg',
    'https://speed.hetzner.de/100MB.bin',
    'https://speed.hetzner.de/1GB.bin'
];

const url = urls[0];
const postUrl = `https://postman-echo.com/post`;

function buildPostFormData(){

    //Some form size to show upload progress process better
    const formData = new FormData();

    for(let x = 0; x < 5000; x++){

        formData.append(x, 'My data ' + x);
    }

    return formData;
}

const tests = {

    native: {

        get(){

            const xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.responseType = 'blob';
            xhr.onprogress = function(e){

                console.log('ondownloadprogress', e);
            };

            xhr.onload = function (event) {

                console.log('load done', xhr.response);

                if(url === urls[0]) {

                    const urlCreator = window.URL || window.webkitURL;
                    const imageUrl = URL.createObjectURL(this.response);
                    const el = document.createElement('img');
                    el.src = imageUrl;
                    document.body.append(el);
                }
            }

            xhr.send();
        },
        post(){

            const xhr = new XMLHttpRequest();
            xhr.open('POST', postUrl, true);

            xhr.onprogress = (e) => {

                console.log('ondownloadprogress', e)
            }

            xhr.upload.onprogress = (e) => {

                console.log('onuploadprogress', e)
            };

            // xhr.upload.addEventListener('progress', (e) => {
            //
            //     console.log('onuploadprogress 2', e)
            //
            // }, false);
            //
            // xhr.upload.addEventListener('progress', (e) => {
            //
            //     console.log('onuploadprogress 3', e)
            //
            // }, false);

            xhr.onload = () => {

                console.log('done upload')
            }

            xhr.send(buildPostFormData());
        }
    },
    axios: {

        get(){

            axios.get(url, {

                responseType: 'blob',
                onDownloadProgress(e){

                    console.log('ondownloadprogress', e)
                },
                onUploadProgress(e){

                    console.log('onuploadprogress', e);
                }

            }).then(result => {

                console.log(result);

                if(url === urls[0]) {

                    const urlCreator = window.URL || window.webkitURL;
                    const imageUrl = URL.createObjectURL(result.data);
                    const el = document.createElement('img');
                    el.src = imageUrl;
                    document.body.append(el);
                }

            }).catch(e => {

                console.log(e);
            })
        },
        post(){

            axios.post(

                postUrl,
                buildPostFormData(),
                {
                    headers: {

                        'Content-Type': 'multipart/form-data'
                    },
                    onDownloadProgress(e){

                        console.log('ondownloadprogress', e)
                    },
                    onUploadProgress(e){

                        console.log('onuploadprogress', e);
                    }

            }).then(res => {

                console.log(res);

            }).catch(e => {

                console.log(e);
            });
        }
    }
};

tests.native.get();

One more thing. In order to download files from web in localhost, its going to be needed to disabled browser CORS policy, in case of chrome see Disable CORS Chrome.

Hope it helps @mydea! Regards.

from pretender.

xg-wang avatar xg-wang commented on July 18, 2024

@ankology nice finding! Would you mind creat a PR with your change?

from pretender.

miccoh1994 avatar miccoh1994 commented on July 18, 2024

#305 (comment)

Would be fantatsic if this was made into a PR, major bummer

from pretender.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.