Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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'); 
  });
});
like image 227
venky royal Avatar asked Aug 15 '26 15:08

venky royal


1 Answers

I was having a similar problem recently. Found this stack overflow hoping for help. Not sure if you are technically having the same problem I was however I was unblocked thanks to help on the Stencil slack account.

In my case I needed to register the components in my test file like I do in the index.

example:

defineCustomElements(window);

Then I just waitFor the component to have the hydrated class:

await waitFor(() => {
      expect(filter).toHaveClass('hydrated');
});
like image 71
Andres F Garcia Avatar answered Aug 18 '26 05:08

Andres F Garcia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!