如何模拟包装器中同一组件上的函数触发的响应?
How to mock out a response triggered by a function on the same component in a wrapper?
我的组件有一个在点击保存按钮时触发的功能。然后基于在包装器中完成提取,然后再次将提取响应作为 prop 向下传递。所以 putFn 属性 接受一个函数,putResponse 接受一个 Promise.
我想模拟包装器并在此测试中仅关注组件,在此示例中为“myComponent”。
给定以下测试设置:
./MyComponent.test.js
function setup() {
let mockPutResponse;
const putMockFn = jest.fn(() => {
mockPutResponse = Promise.resolve(
JSON.stringify({ success: true, loading: false })
);
});
render(<MyComponent putFn={putMockFn} putResponse={mockPutResponse} />);
return { putMockFn };
}
test("MyComponent saves the stuff", async () => {
const { putMockFn } = setup();
const button = screen.getByRole("button", { name: /save changes/i });
userEvent.click(button);
// this passes
expect(putMockFn).toHaveBeenCalled();
// this does not pass since the component shows this message
// based on the putResponse property
expect(await screen.findByText(/saved successfully/i)).toBeInTheDocument();
});
如何模拟传递到 putResponse 的 return 值 属性?
我要测试的组件是这样的:
./MyComponent.js
import React from "react";
const MyComponent = ({ putFn, putResponse }) => {
return (
<form onSubmit={putFn}>
{putResponse?.loading && <p>Loading...</p>}
{putResponse?.success && <p>saved succesfully</p>}
<label htmlFor="myInput">My input</label>
<input name="myInput" id="myInput" type="text" />
<button>Save changes</button>
</form>
);
};
export default MyComponent;
它被一种包装器使用,类似于:
./App.js(任意码)
import React, { useState } from "react";
import MyComponent from "./MyComponent";
export default function App() {
const [wrapperPutResponse, setWrapperPutResponse] = useState();
const handlePut = e => {
e.preventDefault();
setWrapperPutResponse({ loading: true });
// timeout, in the actual app this is a fetch
setTimeout(function() {
setWrapperPutResponse({ success: true, loading: false });
}, 3000);
};
return <MyComponent putFn={handlePut} putResponse={wrapperPutResponse} />;
}
创建沙箱:codesandbox.io/s/bold-cloud-2ule8?file=/src/MyComponent.test.js
您可以创建一个 Wrapper
组件来渲染和控制 MyComponent
import React, { useState, useEffect } from "react";
import { screen, render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import MyComponent from "./MyComponent";
const mockPutResponse = jest.fn()
function setup() {
const Wrapper = () => {
const [clicked, setClicked] = useState(false)
const response = clicked ? { success: true, loading: false} : null
useEffect(() => {
mockPutResponse.mockImplementation(() => {
setClicked(true)
})
}, [])
return <MyComponent putFn={mockPutResponse} putResponse={response} />
}
render(<Wrapper />);
}
test("MyComponent saves the stuff", async () => {
setup()
// expect(await screen.findByText(/loading.../i)).toBeInTheDocument();
const button = screen.getByRole("button", { name: /save changes/i });
userEvent.click(button);
// this passes
expect(mockPutResponse).toHaveBeenCalled();
// had some issue with expect acting up when using the toBeInDocument assertion
// so I used this one instead
const text = await screen.findByText(/saved succesfully/i)
expect(text).toBeTruthy()
});
我的组件有一个在点击保存按钮时触发的功能。然后基于在包装器中完成提取,然后再次将提取响应作为 prop 向下传递。所以 putFn 属性 接受一个函数,putResponse 接受一个 Promise.
我想模拟包装器并在此测试中仅关注组件,在此示例中为“myComponent”。
给定以下测试设置:
./MyComponent.test.js
function setup() {
let mockPutResponse;
const putMockFn = jest.fn(() => {
mockPutResponse = Promise.resolve(
JSON.stringify({ success: true, loading: false })
);
});
render(<MyComponent putFn={putMockFn} putResponse={mockPutResponse} />);
return { putMockFn };
}
test("MyComponent saves the stuff", async () => {
const { putMockFn } = setup();
const button = screen.getByRole("button", { name: /save changes/i });
userEvent.click(button);
// this passes
expect(putMockFn).toHaveBeenCalled();
// this does not pass since the component shows this message
// based on the putResponse property
expect(await screen.findByText(/saved successfully/i)).toBeInTheDocument();
});
如何模拟传递到 putResponse 的 return 值 属性?
我要测试的组件是这样的:
./MyComponent.js
import React from "react";
const MyComponent = ({ putFn, putResponse }) => {
return (
<form onSubmit={putFn}>
{putResponse?.loading && <p>Loading...</p>}
{putResponse?.success && <p>saved succesfully</p>}
<label htmlFor="myInput">My input</label>
<input name="myInput" id="myInput" type="text" />
<button>Save changes</button>
</form>
);
};
export default MyComponent;
它被一种包装器使用,类似于:
./App.js(任意码)
import React, { useState } from "react";
import MyComponent from "./MyComponent";
export default function App() {
const [wrapperPutResponse, setWrapperPutResponse] = useState();
const handlePut = e => {
e.preventDefault();
setWrapperPutResponse({ loading: true });
// timeout, in the actual app this is a fetch
setTimeout(function() {
setWrapperPutResponse({ success: true, loading: false });
}, 3000);
};
return <MyComponent putFn={handlePut} putResponse={wrapperPutResponse} />;
}
创建沙箱:codesandbox.io/s/bold-cloud-2ule8?file=/src/MyComponent.test.js
您可以创建一个 Wrapper
组件来渲染和控制 MyComponent
import React, { useState, useEffect } from "react";
import { screen, render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import MyComponent from "./MyComponent";
const mockPutResponse = jest.fn()
function setup() {
const Wrapper = () => {
const [clicked, setClicked] = useState(false)
const response = clicked ? { success: true, loading: false} : null
useEffect(() => {
mockPutResponse.mockImplementation(() => {
setClicked(true)
})
}, [])
return <MyComponent putFn={mockPutResponse} putResponse={response} />
}
render(<Wrapper />);
}
test("MyComponent saves the stuff", async () => {
setup()
// expect(await screen.findByText(/loading.../i)).toBeInTheDocument();
const button = screen.getByRole("button", { name: /save changes/i });
userEvent.click(button);
// this passes
expect(mockPutResponse).toHaveBeenCalled();
// had some issue with expect acting up when using the toBeInDocument assertion
// so I used this one instead
const text = await screen.findByText(/saved succesfully/i)
expect(text).toBeTruthy()
});