FileSaver.js icon indicating copy to clipboard operation
FileSaver.js copied to clipboard

Using Mocha to test file download using file-saver in a react project, gives "ReferenceError: HTMLAnchorElement is not defined" error

Open roshmani opened this issue 5 years ago • 9 comments

I am trying to test the file-download on click of a button in a react project, which uses 'saveAs' from npm file-saver The function for downloading is as follows :

const downloadFile = (csvData) => {
    const dataFile = new Blob([csvData], {
        type: 'text/csv;charset=utf-8;'
    });
    saveAs(
        dataFile,
        `filename.csv`
    );
};

A button component uses this function which is passed as prop to it and is called 'onClick'. The test is as follows :


describe('<ExportButton/>', () => {
    let wrapper, props;

    beforeEach(() => {
        props = {
            ...defaultProps,
            handleOnClick: expect.createSpy(),
            downloadFile: expect.createSpy().andReturn(() => {})
        };

        wrapper = shallow(<ExportButton {...props} />);
    });

    afterEach(() => {
        expect.restoreSpies();
    });

   
    it('should call the downloadFile and save the file in location specified', (done) => {
        wrapper.find('Button').simulate('click');
        setTimeout(() => {
            expect(props.downloadFile).toHaveBeenCalled();
            done();
        }, 50);
    });
});

On running the test it gives

ReferenceError: HTMLAnchorElement is not defined    
    at /node_modules/file-saver/src/FileSaver.js:75:19
    at /node_modules/file-saver/dist/FileSaver.min.js:1:106
    at Object.<anonymous> (/node_modules/file-saver/dist/FileSaver.min.js:1:154)......

error and test fails. The file download seem to work though.

what can be done to get it working ? Please help. If i use the 'saveAs' from here https://www.npmjs.com/package/save-as it works just fine in the tests.

roshmani avatar Aug 11 '20 15:08 roshmani

I would probably not test the file saving feature in a unit test. FileSaver is meant to run in a browser anyway

jimmywarting avatar Aug 11 '20 15:08 jimmywarting

The tests for the component using the file-saver also doesn't run, and as you can see i am just spying on the function which uses it and not testing the download. Is there any other dependency i need to configure when i use this ?

roshmani avatar Aug 12 '20 06:08 roshmani

Same problem here

Aarbel avatar Sep 01 '20 15:09 Aarbel

@roshmani have you found a solution ?

Aarbel avatar Sep 01 '20 15:09 Aarbel

@roshmani

Adding HTMLAnchorElement with JSDOM and the root of my tests solves the problem on my side.

My code:

const jsdom = require("jsdom");
const { JSDOM } = jsdom;

const { document } = new JSDOM(``, {
  url: "http://localhost",
}).window;
global.document = document;
global.window = document.defaultView;
global.HTMLElement = window.HTMLElement;
global.HTMLAnchorElement = window.HTMLAnchorElement;

Aarbel avatar Sep 01 '20 18:09 Aarbel

Problem is not only in compatibility with Mocha, but also in compatibility on mobile devices. I created PR for fix in year 2019, see https://github.com/eligrey/FileSaver.js/pull/533, but still not merged...

liborm85 avatar Sep 02 '20 04:09 liborm85

@roshmani have you found a solution ?

unfortunately i have not found the solution...i will try adding the

global.HTMLElement = window.HTMLElement;
global.HTMLAnchorElement = window.HTMLAnchorElement;

rest of them are already there.

roshmani avatar Sep 02 '20 06:09 roshmani

@roshmani

Adding HTMLAnchorElement with JSDOM and the root of my tests solves the problem on my side.

My code:

const jsdom = require("jsdom");
const { JSDOM } = jsdom;

const { document } = new JSDOM(``, {
  url: "http://localhost",
}).window;
global.document = document;
global.window = document.defaultView;
global.HTMLElement = window.HTMLElement;
global.HTMLAnchorElement = window.HTMLAnchorElement;

Thank you very much , the tests seems to pass after adding the two statements.

roshmani avatar Sep 02 '20 06:09 roshmani

@roshmani Adding HTMLAnchorElement with JSDOM and the root of my tests solves the problem on my side. My code:

const jsdom = require("jsdom");
const { JSDOM } = jsdom;

const { document } = new JSDOM(``, {
  url: "http://localhost",
}).window;
global.document = document;
global.window = document.defaultView;
global.HTMLElement = window.HTMLElement;
global.HTMLAnchorElement = window.HTMLAnchorElement;

Thank you very much , the tests seems to pass after adding the two statements.

This worked for me too. Thanks @Aarbel

gabbarnarwaria avatar Oct 06 '22 04:10 gabbarnarwaria