Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Items do not render in tests (using jest and testing-library/react) #200

Open
jake-miles opened this issue Jan 2, 2022 · 1 comment
Open

Comments

@jake-miles
Copy link

Expected Behavior

When a test written with jest and testing-library/react renders a MultiSelect component with a non-empty list of items, the items are rendered in the MultiSelect component, i.e. appear in the result of testing-library's screen.debug and are queryable using testing-library dom element queries.

Actual Behavior

The rendered component does not include the items in the rendered DOM, although it does include the number selected (e.g. "1 selected") in the selection list component, implying that the component's state is up-to-date, and something about the test environment or MultiSelect configuration is preventing the items themselves from rendering.

Steps to Reproduce the Problem

  1. In package.json (among other things - I believe these are the relevant packages)
 "@kenshooui/react-multi-select": "1.1.6",  
  "react": "16.11.0",
 "jest-cli": "24.9.0",
 "@testing-library/dom": "8.11.1",
 "@testing-library/jest-dom": "5.16.1",
 "@testing-library/react": "12.1.2",
  1. Test:

import MultiSelect from '@kenshooui/react-multi-select';
import { render, screen } from '@testing-library/react';

describe("testing multiselect rendering", () => {
it.only("renders something in the id list", async () => {

  const items = [{ id: 'xyz1', label: 'xyz1' }];
  let selected = items;
  
  const setSelected = ids => selected = ids;
  
  await render(<MultiSelect
	     name="selected_items"
	     items={items}
	     selectedItems={selected}
	     onChange={setSelected}
	   />);

  // would normally use getBy or findBy - using queryBy to more easily demo the issue
  const numSelected = screen.queryByText("1 selected");
  expect(numSelected).not.toBeNull();  // => assertion passes

  const item = screen.queryByText("xyz1");
  expect(item).not.toBeNull();  => // assertion fails
});

});


The first assertion passes and the second one fails, i.e. "1 selected" is in the rendered DOM, implying that the component's state is up to date, but the item's label "xyz1" is not, meaning that the selected item itself isn't rendering. 

Likewise, the result of `screen.debug()` shows:

            <div
              class="kn-selection_status__status___1qxE9"
            >
              1 selected
            </div>

which is the element in the target list on the right that reports the number of selected items in it,
and includes the list component rendered, but no items within it:
          <div
            style="overflow: visible; height: 0px; width: 0px;"
          >
            <div
              aria-label="grid"
              aria-readonly="true"
              class="ReactVirtualized__Grid ReactVirtualized__List kn-list__list___22Wuc"
              role="grid"
              style="box-sizing: border-box; direction: ltr; height: -47px; position: relative; width: 0px; will-change: transform; overflow-x: hidden; overflow-y: auto;"
              tabindex="0"
            />
          </div>
        </div>

Likewise, the source list on the left renders its top-level grid component, but no items:
            <div
              class="kn-item_label__label___2fJ5p"
            >
              Select All
            </div>
          </div>
          <div
            style="overflow: visible; height: 0px; width: 0px;"
          >
            <div
              aria-label="grid"
              aria-readonly="true"
              class="ReactVirtualized__Grid ReactVirtualized__List kn-list__list___22Wuc"
              role="grid"
              style="box-sizing: border-box; direction: ltr; height: -87px; position: relative; width: -1px; will-change: transform; overflow-x: hidden; overflow-y: auto;"
              tabindex="0"
            />
          </div>

When I inspect the DOM in a browser, those list components contains other elements rendering the list items.

Is this a missing configuration option? Perhaps something rendering itself differently based on device that isn't rendering in the  test environment's dom?

My end goal is to write tests confirming that actions taken outside of this component in the surrounding page are updating this component's state correctly (i.e. my end goal is not to test MutiSelect itself, but that the set of currently-selected items is being propagated to it correctly, because other components in the page can also change the selection).

Thanks for any help with this.

## Specifications

  - Version: 1.1.6
  - Platform: OS X, node 17.0.1
  - Subsystem: react 16.11.0
@ttlekich
Copy link

ttlekich commented Oct 11, 2022

Spent some time on this thinking it was only react-virtualized's 'AutoSizer' that was causing issues. However, it seems like the auto height higher order component throws in some issues too. Using these spies, I was able to render items in the dropdown:

const height = 100 // set to whatever you need
const width = 100 // set to whatever you need
jest.spyOn(HTMLElement.prototype, 'offsetWidth', 'get').mockReturnValue(
    width
)
jest.spyOn(
    HTMLElement.prototype,
    'clientHeight',
    'get'
).mockImplementation(() => height)

For reference,

https://github.com/kenshoo/react-multi-select/blob/master/src/components/with_responsive_height.js#L52
and (AutoSizer) https://github.com/kenshoo/react-multi-select/blob/master/src/components/list/items_list.js#L69

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants