SAP / ui5-webcomponents-react

A wrapper implementation for React of the UI5 Web Components that are compliant with the SAP Fiori User Experience
https://sap.github.io/ui5-webcomponents-react/
Apache License 2.0
435 stars 97 forks source link

How to test events of components in typescript with jest #3975

Closed I347684 closed 1 year ago

I347684 commented 1 year ago

Hello, I'm using typescript and having a difficult time to test the events of some elements like a Select.

const ThemeSwitch = () => {
  const { t } = useTranslation()

  const [selectedTheme, setSelectedTheme] = useState<string>(themeOptions[0].value)

  const onChange = (event: Ui5CustomEvent<SelectDomRef, { selectedOption: HTMLElement }>) => {
    setSelectedTheme(event.detail.selectedOption.dataset.value || selectedTheme)
    setTheme(event.detail.selectedOption.dataset.value || selectedTheme)
  }

  return (
    <Select onChange={onChange} style={spacing.sapUiTinyMargin}>
      {themeOptions &&
        themeOptions.map((option) => {
          return (
            <Option key={option.value} data-value={option.value} selected={option.value === selectedTheme}>
              {t(option.title)}
            </Option>
          )
        })}
    </Select>
  )
}

I have this simple ThemeSwitch component using a Select and I want to test that when the onChange is fired, the option that I pass into the event is selected.

it('Should change the selected theme on click', () => {
    const { container } = render(<ThemeSwitch />)
    const selector = container.querySelector('ui5-select')
   //**1 try**
    const event = new CustomEvent('change', { detail: { selectedOption: { dataset: { value: 'sap_belize'}} } }) as Ui5CustomEvent
    fireEvent.change(selector, event) - **Event is triggered but details is always empty**
   //**2 try**
   fireEvent.change(selector, { detail: { selectedOption: { dataset: { value: 'sap_belize'}} } })
  fireEvent.change(selector, event) - **Event is triggered but details is always empty**

    const currentTheme = getTheme()
    expect(currentTheme).toBe('sap_belize')
  })

already tried to create a event with same type as received in the onChange : (event: Ui5CustomEvent<SelectDomRef, { selectedOption: HTMLElement }>)

Like this:

const event: Ui5CustomEvent<SelectDomRef, { selectedOption: HTMLElement }> = { detail: { selectedOption: { dataset: { value: 'sap_belize' } } } } fireEvent.change(selector, event)

But I have an error because of all he missing properties in the HTMLElement interface
Type '{ dataset: { value: string; }; }' is missing the following properties from type 'HTMLElement': accessKey, accessKeyLabel, autocapitalize, dir, and 274 more.

Similar issue when trying to test that a popover is opened when a button is clicked.

image

If you could please help me out :) 
MarcusNotheis commented 1 year ago

Hey @I347684, thanks for reaching out!

Let me try to answer the part with the PopoverDomRef first because events are unfortunately a bit more complex. Actually, the example in our seed project is incorrect, we'll update that. Basically the ref has to be created via createRef<TYPE>() instead of trying to create the object on your own.

Here's an example of how this test works in TypeScript (codesandbox):

import { fireEvent, render, screen } from "@testing-library/react";
import { Button, Popover, PopoverDomRef } from "@ui5/webcomponents-react";
import { createRef } from "react";

test("should open popover", () => {
  const ref = createRef<PopoverDomRef>();
  render(
    <>
      <Popover ref={ref}>Hello World!</Popover>
      <Button onClick={(e) => ref.current.showAt(e.target)}>
        Open Popover
      </Button>
    </>
  );
  fireEvent.click(screen.getByText("Open Popover"));
});
MarcusNotheis commented 1 year ago

I played a bit around with testing the change event and I'm sorry to say that this is most likely not possible using jest with jsdom as testing environment.

The root cause is that all event handlers in UI5 Web Components are only registered after the UI5 Web Components core has been booted. Unfortunately, jsdom uses an very outdated CSS Model (cssom) which is unmaintained and fails to parse the CSS stylesheet, so the core never boots up and hence no event listeners get registered.

We're currently exploring Cypress Component Tests because these tests run in a real browser and all the UI5 Web Components work as intended. As soon as we are certain that Cypress Component Tests are the way to go, we'll update our testing docs.

Lukas742 commented 1 year ago

Hi @I347684

our updated documentation about testing can now be found here.