Comments (8)
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.
No, sadly not!
from pretender.
This is kind blocking. Without pretender fetch('/image.png')
returns corrent blob with correct size. With pretender it does not.
from pretender.
Any solution found @mydea ? I made a entire app with pretender and found that issue too..
from pretender.
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.
@ankology nice finding! Would you mind creat a PR with your change?
from pretender.
Would be fantatsic if this was made into a PR, major bummer
from pretender.
Related Issues (20)
- The return type for the request handler should be a response handler and not void. HOT 2
- Intercept XMLHttpRequest through a Service Worker HOT 3
- requestBody missing from types HOT 1
- Proposal: Vendor whatwg-fetch HOT 12
- Cannot read property 'prototype' of undefined (XMLHTTPRequest) HOT 2
- Incorrect "progress" events for requests with FormData HOT 1
- Resolve all manual resolution requests by calling pretender.resolve() with no arguments? HOT 1
- Mocking route with query params HOT 3
- Types for RequestHandler are too strict
- XMLHttpRequest's responseType json is ignored by passthrough
- FormData undefined is not a function
- Implement `prepare` hook to run `yarn build` before `yarn test`
- Server class in index.d.ts does not match Pretender class HOT 1
- Unable to extend verbified methods
- Using happy-dom instead of jsdom? HOT 1
- Passthrough not working with axios 0.21.2+ HOT 4
- Mismatch between types in `pretender.js` and in `index.d.ts`
- Conflict with webpack and ember-auto-import v2 in an emberjs project
- Interference between Pretender and React Server Components HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pretender.