3
<Select
                    inputProps={{ "data-testid": "change-form" }}
                    multiple
                    value={permissionsArr}
                    onChange={handleChange}
                    input={<Input />}
                    renderValue={selected => (
                        <ChipsContainer >
                            { selected.map(value => (
                                <Chip key={value} label={value} />
                            ))}
                        </ChipsContainer >
                    )}
                >
                    {perms.map(name => (
                        <MenuItem key={name} value={name}>{prettyName(name)}</MenuItem>
                    ))}
                </Select>

This is the select element that I am trying to test, Here permissionArr is a list of strings that are displayed. And handleChange is changing the permissionsArr. But when I try to test this:

const labelPermissions = queryByTestId("change-form")
fireEvent.change(labelPermissions, { target: { value:  ["string", "string"] }} );

It doesn't call the onChange event. It might be because value shouldn't be an array is my best guess. I've been stuck on this for a while, any help would be much appreciated.

1 Answer 1

2

Select doesn't really have a change event. The function provided to onChange is called when changes occur due to other events -- generally clicking a MenuItem. I would recommend that you structure your test to use the same interactions as would be done by a user.

Below is an example test using a multiple Select from the documentation:

demo.test.js

import React from "react";
import {
  render,
  fireEvent,
  waitForElementToBeRemoved,
  screen
} from "@testing-library/react";
import Demo from "./demo";
import "@testing-library/jest-dom/extend-expect";

test("display and change select", async () => {
  render(<Demo />);
  // Open the Select
  fireEvent.mouseDown(screen.getByLabelText("Name"));
  // Click the entries you want to select
  fireEvent.click(screen.getByText("Van Henry"));
  fireEvent.click(screen.getByText("April Tucker"));
  // Close the select using Escape or Tab or clicking away
  fireEvent.keyDown(document.activeElement, {
    key: "Escape",
    code: "Escape"
  });
  // Wait for Menu to close
  await waitForElementToBeRemoved(screen.getByText("Oliver Hansen"));
  // Verify selections
  expect(screen.getByLabelText("Name")).toHaveTextContent(
    "Van Henry, April Tucker"
  );
});

and here is the code it is testing:

demo.js

import React from "react";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import Input from "@material-ui/core/Input";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import Select from "@material-ui/core/Select";

const useStyles = makeStyles(theme => ({
  formControl: {
    margin: theme.spacing(1),
    minWidth: 120,
    maxWidth: 300
  },
  chips: {
    display: "flex",
    flexWrap: "wrap"
  },
  chip: {
    margin: 2
  },
  noLabel: {
    marginTop: theme.spacing(3)
  }
}));

const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
  PaperProps: {
    style: {
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
      width: 250
    }
  }
};

const names = [
  "Oliver Hansen",
  "Van Henry",
  "April Tucker",
  "Ralph Hubbard",
  "Omar Alexander",
  "Carlos Abbott",
  "Miriam Wagner",
  "Bradley Wilkerson",
  "Virginia Andrews",
  "Kelly Snyder"
];

function getStyles(name, personName, theme) {
  return {
    fontWeight:
      personName.indexOf(name) === -1
        ? theme.typography.fontWeightRegular
        : theme.typography.fontWeightMedium
  };
}

export default function MultipleSelect() {
  const classes = useStyles();
  const theme = useTheme();
  const [personName, setPersonName] = React.useState([]);

  const handleChange = event => {
    setPersonName(event.target.value);
  };

  return (
    <div>
      <FormControl className={classes.formControl}>
        <InputLabel id="demo-multiple-name-label">Name</InputLabel>
        <Select
          labelId="demo-multiple-name-label"
          id="demo-multiple-name"
          multiple
          value={personName}
          onChange={handleChange}
          input={<Input />}
          MenuProps={MenuProps}
        >
          {names.map(name => (
            <MenuItem
              key={name}
              value={name}
              style={getStyles(name, personName, theme)}
            >
              {name}
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

Edit Select change test

Sign up to request clarification or add additional context in comments.

2 Comments

Yeah that makes more sense, but for some reason, I'm unable to find the MenuItem text displayed using getByText.
@UtkarshMishra I recommend creating a sandbox demonstrating your scenario. I recommend starting with mine and modifying it to be more like your scenario until reproducing your problem. Then include that sandbox in your question (if you haven't already found the solution during that process).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.