Search code examples
reactjsunit-testingjestjsreact-testing-librarystenciljs

How to mock stencil web components by using react testing library?


I've created a separate web component library using Stenicljs and used it in React application, While writing test cases realized that events are not working as expected. I've tried to mock the component but was not able to figure out the proper way of doing it. Definitely need some help..!

stencil web component:

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 && !isWrapper,
      [this.appearance]: this.appearance && !isWrapper,
      [this.size]: this.size && !isWrapper,
      [this.class]: this.class && !isWrapper,
      bold: this.bold && !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>

Currently, I am trying to mock the Stencil button in my react application:

const App = () => {


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

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

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

Below is my test case:

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'); 
  });
});

Solution

  • Finally was able to find the solution to this.

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