Как имитировать веб-компоненты трафарета с помощью библиотеки тестирования react?

#reactjs #unit-testing #jestjs #react-testing-library #stenciljs

Вопрос:

Я создал отдельную библиотеку веб-компонентов с помощью Stenicljs и использовал ее в приложении React, пока писал тестовые примеры, понял, что события работают не так, как ожидалось. Я пытался издеваться над компонентом, но не смог понять, как это правильно сделать. Определенно нужна помощь..!

веб-компонент трафарета:

 import { Component, ComponentInterface, Element, Event, EventEmitter, h, Host, Prop } from '@stencil/core';
import { ButtonAppearance, ButtonSize, ButtonType } from '../types';
import classnames from 'classnames';
import { generateUniqueId } from '../../utils/utils';
@Component({
  tag: 'stencil-button',
  styleUrl: 'stencil-button.scss',
  shadow: true,
})
export class StencilButton implements ComponentInterface {
  @Element() el!: HTMLElement;

  @Prop({ attribute: 'autofocus' }) autoFocus?: boolean;

  @Prop({ mutable: true }) value: string;

  @Prop() disabled?: boolean;

  @Prop() name?: string;

  @Prop() form?: string;

  @Prop() stencilHidden?: boolean;

  @Prop() type?: ButtonType = 'button';

  @Prop() class: string;

  @Prop() appearance: ButtonAppearance;

  @Prop() size: ButtonSize;

  @Prop() bold: boolean;

  @Prop() stencilId: any;

  @Prop() inLine: boolean;

  private handleClick = (e: Event) => {
    if (this.disabled) {
      e.preventDefault();
      e.stopPropagation();
    }
    const form = this.el.closest('form');
    if (form) {
      e.preventDefault();
      const dummyButton = document.createElement('button');
      dummyButton.type = this.type;
      dummyButton.style.display = 'none';
      dummyButton.name = 'dummy-button';
      form.appendChild(dummyButton);
      dummyButton.click();
      dummyButton.remove();
    }
  };
  @Event() stencilClick!: EventEmitter<void>;
  private onHandle = e => {
    this.stencilClick.emit(e);
  };
  private buttonId = `gt-button-${generateUniqueId()}`;

  render () {
    const isWrapper = this.appearance === 'wrapper';
    const classList = classnames({
      btn: true amp;amp; !isWrapper,
      [this.appearance]: this.appearance amp;amp; !isWrapper,
      [this.size]: this.size amp;amp; !isWrapper,
      [this.class]: this.class amp;amp; !isWrapper,
      bold: this.bold amp;amp; !isWrapper,
      wrapper: isWrapper,
      stencilInline: this.inLine,
    });
    const hostStyles = classnames({
      stencilInline: this.inLine
    })
    return (
      <Host onClick={this.handleClick} class={hostStyles}>
        <button
          class={classList}
          id={this.stencilId ? this.stencilId : this.buttonId}
          onClick={this.onHandle}
          autoFocus={this.autoFocus}
          hidden={this.stencilHidden}
          disabled={this.disabled}
          name={this.name}
          type={this.type}
          form={this.form}
        >
          <slot></slot>
        </button>
      </Host>
    );
  }
} 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> 

В настоящее время я пытаюсь издеваться над кнопкой трафарета в своем приложении react:

 const App = () => {


const [btnvalue, setbtnvalue] = useState(0);

  const increment = () => {
    setbtnvalue(btnvalue   1);
  };

  return (
    <div>
      <StencilButton onStencilClick={increment} data-testid='click-btn'>
        {btnvalue}
      </StencilButton >
    </div>
  );
};
 

Ниже приведен мой тестовый пример:

 describe('counter test cases', () => {
  it('updated counter on click', () => {  
    const clickBtn = getByTestId('click-btn');
    fireEvent.click(clickBtn);
    console.log(clickBtn.textContent);
    expect(clickBtn.textContent).toBe('1'); 
  });
});
 

Комментарии:

1. Возможно, вам потребуется обернуть fireEvent.нажмите или ожидание в ожидание waitFor (() = > { … });. В этом не должно быть необходимости, так как библиотека тестирования реакции обертывает триггер события в act (), но, по моему опыту, это иногда необходимо.

Ответ №1:

Недавно у меня была похожая проблема. Нашел это переполнение стека в надежде на помощь. Не уверен, что технически у вас та же проблема, что и у меня, однако я был разблокирован благодаря помощи в учетной записи Stencil slack.

В моем случае мне нужно было зарегистрировать компоненты в моем тестовом файле, как я делаю в индексе.

пример:

 defineCustomElements(window);
 

Затем я просто жду, пока компонент получит гидратированный класс:

 await waitFor(() => {
      expect(filter).toHaveClass('hydrated');
});
 

Ответ №2:

Наконец-то удалось найти решение этой проблемы.

 import StencilButton from 'stencil-components';

jest.mock('stencil-components', () => ({
  StencilButton: (props) => {
    return (
      <button
        {...props}
      />
    );
  },
}));