Skip to content

Commit

Permalink
chore(docs): started creating testing recipes
Browse files Browse the repository at this point in the history
  • Loading branch information
mlaursen committed Jan 13, 2025
1 parent b2b07ef commit 2488f8a
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 3 deletions.
141 changes: 141 additions & 0 deletions apps/docs/src/app/(main)/(markdown)/testing/recipes/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Recipes

This page will provide common testing recipes for components through ReactMD.

# Autocomplete

TODO

# Checkbox

TODO

# Dialog/Sheet

TODO

# Expansion Panel

TODO

# Menu

TODO

# Radio

TODO

# Select

> All of these examples will use the [Simple Select](/components/select#simple-select) example code.
## Find and Change Value

This example showcases how to:

- find the `Select` component
- find and verify the current selected option
- change the selected option

```tsx
import { screen, rmdRender, userEvent } from "@react-md/core/test-utils";

it("should be able to change value", async () => {
const user = userEvent.setup();
rmdRender(<SimpleSelect />);

// this is the clickable element that allows the listbox of options to appear
const select = screen.getByRole("combobox", { name: "Label" });
// this stores the current value
const selectValue = screen.getByRole("textbox", { hidden: true });
expect(selectValue).toHaveValue("");

await user.click(select);
// the `name` should be the accessible text in any of the available options
await user.click(screen.getByRole("option", { name: "Option 1" }));
expect(selectValue).toHaveValue("a");

await user.click(select);

// the `Option 1` should now be selected
expect(() =>
screen.getByRole("option", { name: "Option 1", selected: true })
).not.toThrow();
});
```

## Verify the Display Value

This example showcases how to find and verify the selected option's display
value while the Select listbox is closed using the `getSelectParts` test util query.

```tsx
import {
getSelectParts,
screen,
rmdRender,
userEvent,
} from "@react-md/core/test-utils";

it("should be able to verify the display value", async () => {
const user = userEvent.setup();
rmdRender(<SimpleSelect />);

const { select, selectValue, selectDisplay } = getSelectParts({
name: "Label",
});
// this isn't required, but added to show what element this is
expect(selectDisplay).toHaveClass("rmd-selected-option");

// there is currently no selected value
expect(selectDisplay).toHaveTextContent("");

await user.click(select);
await user.click(screen.getByRole("option", { name: "Option 1" }));
expect(selectValue).toHaveValue("a");
expect(selectDisplay).toHaveTextContent("Option 1");
});
```

# Slider

TODO

# Snackbar

TODO

# Switch

## Find and Toggle

The `Switch` is an extension of an `<input type="checkbox">` with
`role="switch"`, so the element can be changed just like a `Checkbox`.

```tsx
import { screen, rmdRender, userEvent } from "@react-md/core/test-utils";

it("should be able to change the checked state", async () => {
const user = userEvent.setup();
rmdRender(<Switch label="Label" />);

const switchElement = screen.getByRole("switch", { name: "Label" });
expect(switchElement).not.toBeChecked();

await user.click(switchElement);
expect(switchElement).toBeChecked();
});
```

# Tabs

TODO

# Tooltip

TODO

# Tree

TODO
5 changes: 5 additions & 0 deletions apps/docs/src/components/MainLayout/navItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,11 @@ export const navItems: readonly NavigationItem[] = [
href: "/quickstart",
children: "Quickstart",
},
{
type: "route",
href: "/recipes",
children: "Recipes",
},
{
type: "route",
href: "/polyfills",
Expand Down
9 changes: 6 additions & 3 deletions packages/core/src/form/__tests__/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { FontIcon } from "../../icon/FontIcon.js";
import { CircularProgress } from "../../progress/CircularProgress.js";
import {
act,
getSelectParts,
rmdRender,
screen,
userEvent,
Expand Down Expand Up @@ -41,9 +42,11 @@ function render<Value extends string = string>(
) {
const user = userEvent.setup();
const { rerender } = rmdRender(<Test {...props} />);
const select = screen.getByRole("combobox", { name: "Select" });
const selected = screen.getByTestId("selected");
const selectValue = screen.getByRole("textbox", { hidden: true });
const {
select,
selectValue,
selectDisplay: selected,
} = getSelectParts({ name: "Select" });

return {
rerender: (props: Partial<SelectProps<Value>>) => {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/test-utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from "@testing-library/react";
export * from "@testing-library/user-event";
export * from "./mocks/match-media.js";
export * from "./render.js";
export * from "./utils/queries.js";
export * from "./utils/resize-observer.js";
74 changes: 74 additions & 0 deletions packages/core/src/test-utils/utils/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
type BoundFunctions,
type ByRoleOptions,
type queries,
screen,
within,
} from "@testing-library/dom";

/**
* @since 6.0.0
*/
export interface SelectParts {
select: HTMLDivElement;
selectValue: HTMLInputElement;
selectDisplay: HTMLDivElement;
}

/**
* @since 6.0.0
*/
export interface GetSelectPartsOptions extends ByRoleOptions {
/** @defaultValue `screen` */
container?: BoundFunctions<typeof queries>;
}

/**
* @example Simple Example
* ```tsx
* import {
* getSelectParts,
* screen,
* rmdRender,
* userEvent,
* } from "@react-md/core/test-utils";
*
* it("should be able to verify the display value", async () => {
* const user = userEvent.setup();
* rmdRender(<SimpleSelect />);
*
* const { select, selectValue, selectDisplay } = getSelectParts({
* name: "Label",
* });
* // this isn't required, but added to show what element this is
* expect(selectDisplay).toHaveClass("rmd-selected-option");
*
* // there is currently no selected value
* expect(selectDisplay).toHaveTextContent("");
*
* await user.click(select);
* await user.click(screen.getByRole("option", { name: "Option 1" }));
* expect(selectValue).toHaveValue("a");
* expect(selectDisplay).toHaveTextContent("Option 1");
* });
* ```
*
* @since 6.0.0
*/
export function getSelectParts(options: GetSelectPartsOptions): SelectParts {
const { container = screen, ...byRoleOptions } = options;
const select = container.getByRole<HTMLDivElement>("combobox", byRoleOptions);
const selectValue = within(select).getByRole<HTMLInputElement>("textbox", {
hidden: true,
});
const selectDisplay = select.firstElementChild;
if (!(selectDisplay instanceof HTMLDivElement)) {
throw new Error("Unable to find the `Select` display value element");
}

return {
select,
selectValue,
selectDisplay,
};
}

0 comments on commit 2488f8a

Please sign in to comment.