capricorn86 / happy-dom

A JavaScript implementation of a web browser without its graphical user interface
MIT License
3.27k stars 200 forks source link

jsdom and happy-dom differs in ArrayBuffer handling for File instances #704

Open CSchulz opened 1 year ago

CSchulz commented 1 year ago

Describe the bug During migration from jsdom to happy-dom I have encountered an issue with different File instance handling which leads to failing unit tests. The file size is different between jsdom and happy-dom.

To Reproduce

const file = new File([new ArrayBuffer(2)], 'test', { type: 'image/png'})
// expect 20 to equal 2
expect(file.length).toEqual(2)

Expected behavior File length should be 2.

Screenshots If applicable, add screenshots to help explain your problem.

Device:

Additional context I have already traced it down to the instanceof check of ArrayBuffer:

https://github.com/capricorn86/happy-dom/blob/e49546cfb18fcd339db6ca0274acd8345e011a2d/packages/happy-dom/src/file/Blob.ts#L31-L41

This doesn't work correctly. I think there is an issue with the prototype check leading to instanceof gets falsy. And in this case the given ArrayBuffer is handled by the last branch with conversion to String.

For this situation jsdom uses an util generated by webidl2js:

https://github.com/jsdom/jsdom/blob/8e3a568d504353270691b5955af505155ae368bf/lib/jsdom/living/file-api/Blob-impl.js#L3-L21

https://github.com/jsdom/jsdom/blob/8e3a568d504353270691b5955af505155ae368bf/scripts/webidl/convert.js#L169

https://github.com/jsdom/webidl2js/blob/e33357d715ae33d41a8fe109545de3ffcb965e78/lib/output/utils.js#L113-L122

vikaschoudharycs097 commented 3 months ago

Facing similar issue. The Image Blob to data URL (reader.readAsDataURL(blob)) is not working as expected - Sample Code

function blobToDataURI(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.addEventListener('load', (e) => {
      resolve(e.target.result);
    });
    reader.readAsDataURL(blob);
  });
}

const imageUrl = 'https://img.freepik.com/free-psd/3d-square-with-facebook-logo_125540-1565.jpg'
blob = await (await globalThis.fetch(imageUrl)).blob();
console.log(`blob instanceof Blob: ${blob instanceof Blob}`);  // Printing false instead of true
const base64EncodedImageUrl = await blobToDataURI(blob);
console.log(base64EncodedImageUrl);

Browser Output:

blob instanceof Blob: true
data:image/avif;base64,AAAAHGZ0eXBhdmlmAAAAAGF2a _Continue..._

Nodejs with happy-dom Output

blob instanceof Blob: false
data:image/avif;base64,