Reputation: 2250
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');
});
});
Upvotes: 3
Views: 1971
Reputation: 2250
Finally was able to find the solution to this.
import StencilButton from 'stencil-components';
jest.mock('stencil-components', () => ({
StencilButton: (props) => {
return (
<button
{...props}
/>
);
},
}));
Upvotes: 1
Reputation: 6975
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');
});
Upvotes: 4