Deprecated APIs should not be used typescript:S1874

  • What language is this for?

Typescript

  • Which rule?

Deprecated APIs should not be used typescript:S1874

  • Why do you believe it’s a false-positive/false-negative?

I’m not using the deprecated document.createElement, but the result shows that it is being used.

  • Are you using

SonarQube - Community Edition Version 9.9.1 (build 69595)

  • How can we reproduce the problem? Give us a self-contained snippet of code (formatted text, no screenshots)
export class FileDownloadUtils {
    /**
     * A utility function to download the file.
     *
     * @param fileName string
     * @param data string
     */
    public static downloadFile(fileName: string, data: Blob): void {
        const downloadLink = document.createElement('a');
        document.body.appendChild(downloadLink);
        const url = window.URL.createObjectURL(data);
        downloadLink.href = url;
        downloadLink.download = fileName;
        downloadLink.click();
        window.URL.revokeObjectURL(url);
    }
}

‘a’ tag is one of members of HTMLElementTagNameMap, so I’m not using the deprecated document.createElement.

import { FileDownloadUtils } from './file-download-utils';

describe('FileDownloadUtils', () => {
    describe('downloadFile()', () => {
        it('should download a file', async () => {
            const mockElement = {} as HTMLAnchorElement;
            mockElement.click = jest.fn();

            jest.spyOn(document, 'createElement').mockImplementation(() => {
                return mockElement;
            });
            jest.spyOn(document.body, 'appendChild').mockImplementation();

            // Mock these methods as we cannot spyOn.
            const createObjectURL = window.URL.createObjectURL;
            const revokeObjectURL = window.URL.revokeObjectURL;
            window.URL.createObjectURL = jest.fn(() => {
                return 'TestFile.json';
            });
            window.URL.revokeObjectURL = jest.fn();

            // The data to be downloaded.
            const data = new Blob(['{Contents: "The Test Json File"}'], {
                type: 'application/json'
            });

            // Download.
            FileDownloadUtils.downloadFile('TestFile.json', data);
            expect(document.createElement).toHaveBeenCalledTimes(1); // !! HERE SonarQube complains "You're using the deprecated createElement!"
            expect(document.body.appendChild).toHaveBeenCalledTimes(1);
            expect(window.URL.createObjectURL).toHaveBeenCalledTimes(1);
            expect(window.URL.createObjectURL).toHaveBeenCalledWith(data);
            expect(mockElement['href']).toBe('TestFile.json');
            expect(mockElement['download']).toBe('TestFile.json');
            expect(mockElement.click).toHaveBeenCalledTimes(1);
            expect(window.URL.revokeObjectURL).toHaveBeenCalledTimes(1);
            expect(window.URL.revokeObjectURL).toHaveBeenCalledWith('TestFile.json');

            // Reset.
            window.URL.createObjectURL = createObjectURL;
            window.URL.revokeObjectURL = revokeObjectURL;
        });
    });
});

From my personal observation, if you use the document.createElement function with no-parenthesis, it seems to unconditionally recognize it as a deprecated createElement.

Hi @RyanShin,

sorry but I’m not sure I’m getting your point. You are using the method here right?

Can you please clarify? Aside from that, probably the deprecation comes from your TS typings? what version of TypeScript are you using?

Thanks,
Victor

1 Like

Hi
I’m using typescript version 4.6.2.
Yes, I’m using the createElement method at two locations.

// #1: ts
const downloadLink = document.createElement('a');
// #2: spec.ts
const mockElement = {} as HTMLAnchorElement;
jest.spyOn(document, 'createElement').mockImplementation(() => {
    return mockElement;
});
expect(document.createElement).toHaveBeenCalledTimes(1);

#2 is the test code(by jest) of #1.

I don’t have any problem with #1.
In case of #2, typescript reports nothing, but sonarqube reports that “The method is deprecated” at bold context below.

expect(document.createElement).toHaveBeenCalledTimes(1);

  • ‘createElement’ is deprecated.
  • Deprecated APIs should not be used typescript:S1874

I found a similar thread that was not resolved in the past.

What my case and Patrik’s case have in common is that we used ‘document.createElement’ without parenthesis.

  • if(document.createElement(‘a’)) → sonarqube does not complain
  • if(document.createElement) → sonarqube complains!

Hello @RyanShin,

it’s clear now, thanks for the clarifications. We have created a ticket to fix this FP.

Thanks!
Victor