如何通过玩笑来测试动态创建元素

问题描述 投票:0回答:1

使用打字稿,我正在尝试测试动态元素。但对此一无所知。有人帮我吗?

这是我的ts文件:

export default class MyClass {
    constructor(){
        this.render();
    }

    render() {

        const el:HTMLInputElement = document.createElement('input') as HTMLInputElement;
        const link:HTMLAnchorElement = document.createElement('a') as HTMLAnchorElement;
        const container:HTMLBodyElement = document.querySelector('body') as HTMLBodyElement;

        link.innerHTML = "Click Me!";
        link.setAttribute('href', '#');
        link.setAttribute('target', '_blank');

        el.setAttribute('type', 'file');
        container.appendChild(el);
        container.appendChild(link);

        el.addEventListener('change', (event) => {
            if('files' in el) {
                const availFile = el.files[0];
                const blob = new Blob([availFile], { type: availFile.type});

                const objectURL = window.URL.createObjectURL(blob);
                link.setAttribute('href', objectURL);

            }
        })
    }
}


new MyClass();

我的test.spec文件:

import MyClass from "./index";
jest.mock('./index');

describe("testing as first", () => {

    it("we can test the constructor", () => {
        const myClass = new MyClass();
        expect(MyClass).toHaveBeenCalledTimes(1);
    });

    it('will render element', () => {
        const myClass = new MyClass();
        myClass.render();
        expect(document.querySelector('input')).toBeTruthy();
        expect(document.querySelector('a')).toBeTruthy();
    })

    it('will render element', () => {
        const myClass = new MyClass();
        myClass.render();

    })

});

覆盖结果:

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |       75 |        0 |       75 |       75 |                   |
 index.ts |       75 |        0 |       75 |       75 |    21,22,23,25,26 |
----------|----------|----------|----------|----------|-------------------|

但是如何测试未覆盖的行?请帮助我。

typescript jestjs jest
1个回答
0
投票

这是单元测试解决方案:

index.ts

export default class MyClass {
  constructor() {
    this.render();
  }

  render() {
    const el: HTMLInputElement = document.createElement('input') as HTMLInputElement;
    const link: HTMLAnchorElement = document.createElement('a') as HTMLAnchorElement;
    const container: HTMLBodyElement = document.querySelector('body') as HTMLBodyElement;

    link.innerHTML = 'Click Me!';
    link.setAttribute('href', '#');
    link.setAttribute('target', '_blank');

    el.setAttribute('type', 'file');
    container.appendChild(el);
    container.appendChild(link);

    el.addEventListener('change', (event) => {
      if ('files' in el) {
        const availFile: File = el.files![0];
        const blob = new Blob([availFile], { type: availFile.type });

        const objectURL = window.URL.createObjectURL(blob);
        link.setAttribute('href', objectURL);
      }
    });
  }
}

index.test.ts

import MyClass from './index';

describe('testing as first', () => {
  let createElement;
  let querySelector;
  let createObjectURL;
  beforeEach(() => {
    createElement = document.createElement;
    querySelector = document.querySelector;
    createObjectURL = window.URL.createObjectURL;
  });
  afterEach(() => {
    jest.restoreAllMocks();
    document.createElement = createElement;
    document.querySelector = querySelector;
    window.URL.createObjectURL = createObjectURL;
  });
  it('should call render method', () => {
    jest.spyOn(MyClass.prototype, 'render').mockReturnValueOnce();
    const myClass = new MyClass();
    expect(myClass.render).toBeCalledTimes(1);
  });
  it('should render element and handle change event if input has files', () => {
    const myClass = new MyClass();
    const mAvailFile = new Blob(['I am file'], { type: 'text/html' });
    const mInput = { setAttribute: jest.fn(), addEventListener: jest.fn(), files: [mAvailFile] };
    const mLink = { setAttribute: jest.fn(), innerHTML: '' };
    const mContainer = { appendChild: jest.fn() };

    document.createElement = jest.fn().mockImplementation((tagName) => {
      switch (tagName) {
        case 'input':
          return mInput;
        case 'a':
          return mLink;
      }
    });
    document.querySelector = jest.fn().mockReturnValueOnce(mContainer);
    mInput.addEventListener.mockImplementationOnce((event, callback) => {
      callback();
    });
    const mObjectURL = 'blob:https://www.google.com/6e165b50-979b-43f6-b685-7163413f0faf';
    window.URL.createObjectURL = jest.fn().mockReturnValueOnce(mObjectURL);
    myClass.render();
    expect(document.createElement).toBeCalledTimes(2);
    expect(document.querySelector).toBeCalledWith('body');
    expect(mLink.innerHTML).toBe('Click Me!');
    expect(mLink.setAttribute.mock.calls[0]).toEqual(['href', '#']);
    expect(mLink.setAttribute.mock.calls[1]).toEqual(['target', '_blank']);
    expect(mInput.setAttribute).toBeCalledWith('type', 'file');
    expect(mContainer.appendChild.mock.calls[0]).toEqual([mInput]);
    expect(mContainer.appendChild.mock.calls[1]).toEqual([mLink]);
    expect(mInput.addEventListener).toBeCalledWith('change', expect.any(Function));
    expect(window.URL.createObjectURL).toBeCalledWith(new Blob([mAvailFile], { type: mAvailFile.type }));
    expect(mLink.setAttribute.mock.calls[2]).toEqual(['href', mObjectURL]);
  });

  it('should render element', () => {
    const myClass = new MyClass();
    const mInput = { setAttribute: jest.fn(), addEventListener: jest.fn() };
    const mLink = { setAttribute: jest.fn(), innerHTML: '' };
    const mContainer = { appendChild: jest.fn() };

    document.createElement = jest.fn().mockImplementation((tagName) => {
      switch (tagName) {
        case 'input':
          return mInput;
        case 'a':
          return mLink;
      }
    });
    document.querySelector = jest.fn().mockReturnValueOnce(mContainer);
    mInput.addEventListener.mockImplementationOnce((event, callback) => {
      callback();
    });
    myClass.render();
    expect(document.createElement).toBeCalledTimes(2);
    expect(document.querySelector).toBeCalledWith('body');
    expect(mLink.innerHTML).toBe('Click Me!');
    expect(mLink.setAttribute.mock.calls[0]).toEqual(['href', '#']);
    expect(mLink.setAttribute.mock.calls[1]).toEqual(['target', '_blank']);
    expect(mInput.setAttribute).toBeCalledWith('type', 'file');
    expect(mContainer.appendChild.mock.calls[0]).toEqual([mInput]);
    expect(mContainer.appendChild.mock.calls[1]).toEqual([mLink]);
    expect(mInput.addEventListener).toBeCalledWith('change', expect.any(Function));
  });
});

单元测试结果覆盖率100%:

 PASS  src/stackoverflow/59833555/index.test.ts (14.002s)
  testing as first
    ✓ should call render method (6ms)
    ✓ should render element and handle change event if input has files (19ms)
    ✓ should render element (13ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.ts |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        16.304s, estimated 17s

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59833555

© www.soinside.com 2019 - 2024. All rights reserved.