preface

In the last article we have had a preliminary experience of component single test, next we will add some common cases for component single test

Determine the style

In react Component, it is common to use some fields to control some styles, or pass in some styles through props. We need to check whether these styles are correctly rendered through single test

Modify the components

Add an optional containerStyle parameter to the TodoHeader component that controls the style of the outermost container

import "./index.css"; Interface TodoHeaderProps {// Title: string; containerStyle? : React.CSSProperties; } export default function TodoHeader({ title, containerStyle }: TodoHeaderProps) { return ( <div className="report-header" style={containerStyle}> <span className="title" data-testid="todo-header-title"> {title} </span> </div> ); }Copy the code

Call modify, add style input parameter

<TodoHeader title=" This is a title "containerStyle={{border: "1px solid blue"}} />Copy the code

Let’s run this to see the effect, PNPM start, and see that the border style is rendered correctly

A single measurement to write

It (' correctly render containerStyle ', () => {const borderStyle = "1px solid blue"; const containerStyle: CSSProperties = { border: borderStyle, }; Const {container} = render(<TodoHeader title=" title "containerStyle={container style} />); expect(container.children[0]).toHaveStyle(`border: ${borderStyle}`); });Copy the code

Here we use an API, toHaveStyle, to determine if our style has been rendered. Because our style is mounted on the top div, we simply use container. Children [0] to fetch the div. Of course it can be changed to the same method we used in the last article. Then let’s execute the test case

pnpm test src/components/__tests__/todo-header.test.tsx
Copy the code

The results are as follows:

Let’s try the failure case. Now if we change the style, let’s see if the use case will fail. Here we change the style of the input parameter to 2px

It (' correctly render containerStyle ', () => {const borderStyle = "1px solid blue"; const containerStyle: CSSProperties = { border: "2px solid blue", }; Const {container} = render(<TodoHeader title=" title "containerStyle={container style} />); expect(container.children[0]).toHaveStyle(`border: ${borderStyle}`); });Copy the code

The expected and received use-cases did not pass the expected and received use-cases did not pass the expected and received use-cases did not pass the expected and received use-cases did not pass the use-cases

Determine the field control style

In a real project, we would pass in some fields and then display different styles. The most common is to display different styles in various states. Here we simulate this scenario

Modify the components

Rewrite the previous code and add an isFinish field to display different backgrounds

import "./index.css"; Interface TodoHeaderProps {// Title: string; // The outermost containerStyle? : React.CSSProperties; // Whether to finish isFinish? : boolean; } export default function TodoHeader({ title, containerStyle, isFinish = false, }: TodoHeaderProps) { return ( <div className="report-header" style={containerStyle}> <span className="title" data-testid="todo-header-title" style={{ background: isFinish ? "red" : "white" }} > {title} </span> </div> ); }Copy the code

Change the call entry code to see the effect, you can see the effect is there (style what not to mock, after all, just to do a single test write)

<TodoHeader title=" This is a title "containerStyle={{border: "1px solid blue"}} isFinish={true} />Copy the code

A single measurement to write

GetByTestId and toHaveStyle to get you started

() => {const {getByTestId} = render(<TodoHeader title=" title "isFinish={true} />); const element = getByTestId("todo-header-title"); expect(element).toHaveStyle(`background: red`); });Copy the code

The results

And don’t forget here, we also have a case where it’s false, because ourisFinishBoolean, only true or false, we have tested the true case above, let’s make sure that the false case also works

() => {const {getByTestId} = render(<TodoHeader title=" title "isFinish={false} />); const element = getByTestId("todo-header-title"); expect(element).toHaveStyle(`background: white`); });Copy the code

The results

Determine properties

In the React Component, it is also common to set attributes to elements, such as passing in the image URL and displaying it correctly in the component. In this case, we can write tests

Rewrite the component

We’re going to add an additional iconUrl entry, and if it comes in we’re going to display it with the IMG tag, look at the code

import "./index.css"; Interface TodoHeaderProps {// Title: string; // The outermost containerStyle? : React.CSSProperties; // Whether to finish isFinish? : boolean; // Icon link iconUrl? : string; } export default function TodoHeader({ title, containerStyle, iconUrl, isFinish = false, }: TodoHeaderProps) { return ( <div className="report-header" style={containerStyle}> {iconUrl && <img src={iconUrl} />} <span className="title" data-testid="todo-header-title" style={{ background: isFinish ? "red" : "white" }} > {title} </span> </div> ); }Copy the code

A single measurement to write

We’re using toHaveAttribute, so you have to pay attention to the input to this API, and we’re using waitFor, so we’re not going to go into that, we’re going to talk about it in more detail

It (` render correct figure mark `, async () = > {const iconUrl = "http://www.abc.com/test.png"; Const {container} = render(<TodoHeader title=" title "iconUrl={iconUrl} />); await waitFor(() => { const imgElement = container.querySelector("img"); expect(imgElement).not.toBeNull(); expect(imgElement).toHaveAttribute("src", iconUrl); }); });Copy the code

The results

Judgment of the children

Children is also relatively common in the component, which gives the component more functions similar to slots. Here is a brief description of my method to judge children. In fact, the idea is relatively simple, but after passing in children, I can judge whether it can be displayed normally by obtaining elements

Rewrite the component

Increased the entry of children using PropsWithChildren directly to show children

import "./index.css"; import { PropsWithChildren } from "react"; Interface TodoHeaderProps {// Title: string; // The outermost containerStyle? : React.CSSProperties; // Whether to finish isFinish? : boolean; // Icon link iconUrl? : string; } export default function TodoHeader({ title, containerStyle, iconUrl, isFinish = false, children, }: PropsWithChildren<TodoHeaderProps>) { return ( <div className="report-header" style={containerStyle}> {iconUrl && <img src={iconUrl} />} <span className="title" data-testid="todo-header-title" style={{ background: isFinish ? "red" : "white" }} > {title} </span> {children} </div> ); }Copy the code

A single measurement to write

It (' render children correctly ', async () => {const id = "childrenId"; Const text = "This is a copy "; Const {getByTestId} = render(<TodoHeader title=" title "> <span data-testid={id}>{text}</span> </TodoHeader>); const childElement = getByTestId(id); expect(childElement).toHaveTextContent(text); });Copy the code

The results

Judge ReactNode

Similar to children, the judgment methods are basically the same

Rewrite the component

import "./index.css"; import { PropsWithChildren, ReactNode } from "react"; Interface TodoHeaderProps {// Title: string; // The outermost containerStyle? : React.CSSProperties; // Whether to finish isFinish? : boolean; // Icon link iconUrl? : string; // Additional information extraInfo? : ReactNode; } export default function TodoHeader({ title, containerStyle, iconUrl, isFinish = false, children, extraInfo, }: PropsWithChildren<TodoHeaderProps>) { return ( <div className="report-header" style={containerStyle}> {iconUrl && <img src={iconUrl} />} <span className="title" data-testid="todo-header-title" style={{ background: isFinish ? "red" : "white" }} > {title} </span> <span className="extra">{extraInfo}</span> {children} </div> ); }Copy the code

A single measurement to write

It (' render extraInfo correctly ', async () => {const id = "extraId"; Const text = "This is a copy "; Const {getByTestId} = render(<TodoHeader title=" "extraInfo={<span data-testid={id}>{text}</span>} />); const childElement = getByTestId(id); expect(childElement).toHaveTextContent(text); });Copy the code

The results

At the end

This blog post has supplemented some of the component tests in other cases and put some of my own experience into the demo. The complete code can be seen in the COMMIT

Series of articles: Learn how to react with fireEvent. Learn how to react with fireEvent. Learn how to react with fireEvent. Github.com/liyixun/rea…