0

我测试了一个反应组件,它应该显示微调器、错误或获取的配方列表。我设法测试了这个组件的加载以及它成功获取数据的时间。我有测试错误的问题。我用 msw 创建了测试服务器,它具有返回错误的路由处理程序。我使用 axios 向服务器发出请求。我认为问题出在这里:axios 发出 3 个请求,直到最后一个响应 useQuery 返回 isLoading=true,isError=false。只有在那之后它才返回 isLoading=false, isError=true。因此,在我对错误 screen.debug() 的测试中显示微调器,并且 errorMessage 返回错误,因为它没有找到带有文本“错误”的渲染元素,该组件应该在发生错误时显示。我能做些什么呢?我没有主意了。


编辑:

  • 我发现 useQuery 中有一个设置,“重试”默认为 3 个请求。我仍然不知道如何在我的测试中处理组件重试请求。

我是反应测试和打字稿的新手。

来自 RecipeList.test.tsx:

import { setupServer } from 'msw/node';
import { rest } from 'msw';
import { QueryClient, QueryClientProvider, QueryCache } from 'react-query';

import RecipeList from './RecipeList';

const server = setupServer(
  rest.get(`${someUrl}`, (req, res, ctx) =>
    res(ctx.status(200), ctx.json(data))
  )
);

const queryCache = new QueryCache();
const RecipeListWithQueryClient = () => {
  const client = new QueryClient();
  return (
    <QueryClientProvider client={client}>
      <RecipeList />
    </QueryClientProvider>
  );
};

// Tests setup
beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
afterEach(() => {
  queryCache.clear();
});

describe('RecipeList', () => {
  //some tests that pass

  describe('while error', () => {
    it('display error message', async () => {
      server.use(
        rest.get(`${someUrl}`, (req, res, ctx) => res(ctx.status(404)))
      );
      render(<RecipeListWithQueryClient />);
      // FOLLOWING CODE RAISE ERROR
      const errorMessage = await screen.findByText(/error/i);
      await expect(errorMessage).toBeInTheDocument();
    });
  });
});

组件代码:

来自 RecipeList.tsx:

import { fetchRecipes } from 'api';

const RecipeList: React.FC = () => {
  const { data, isLoading, isError } = useQuery<
    RecipeDataInterface,
    Error
  >('recipes', fetchRecipes);;

  if (isLoading) {
    return (
      <Spinner>
        <span className="sr-only">Loading...</span>
      </Spinner>
    );
  }

  if (isError) {
    return (
      <Alert >Error occured. Please try again later</Alert>
    );
  }

  return (
    <>
      {data?.records.map((recipe: RecipeInterface) => (
        <RecipeItem key={recipe.id} recipe={recipe.fields} />
      ))}
    </>
  );
};
4

2 回答 2

5

我使用 QueryClient 禁用重试。和 setupServer 模拟网络连接

    import { QueryClient, QueryClientProvider} from 'react-query';
    import { setupServer } from 'msw/node'
    import { rest } from 'msw'

    
const server = setupServer( 
  rest.get('https://reqres.in/api/users', (req, res, ctx) => {      
      return res(
        ctx.status(200),
        ctx.json(userSuccessResponseJson()
            ),
      )
    }),)

beforeAll(() => server.listen())
afterEach(() => {
  server.resetHandlers();
  queryClient.clear();
})
afterAll(() => server.close())


const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retryDelay: 1,
      retry:0,
    },
  },
})
const Wrapper = ({ children }) => (
  <QueryClientProvider client={queryClient}>
    {children}
  </QueryClientProvider>
);



  test('Renders Error text when backend server response with error', async () => {
    server.use(
      rest.get('https://reqres.in/api/users', (req, res, ctx) => {
        return res(ctx.status(403))
      })
    );
  
    render(<Wrapper><CompanyList />)</Wrapper>);
  
    const linkElement = screen.getByText(/Loading/i);
    expect(linkElement).toBeInTheDocument();
  
    await waitFor(() => {      
      const fetchedText = screen.getByText(/Error:/i);      
      expect(fetchedText).toBeInTheDocument();
    })
  });
于 2021-06-08T13:47:17.473 回答
0

我找到的解决方案是为测试设置单独的超时值。

根据文档,在 RTL for waitFor async 方法中:

“默认超时为 1000 毫秒,这将使您处于 Jest 的默认超时 5000 毫秒之下。”

我必须为 RTL 异步函数设置超时选项,但这还不够,因为我收到了一个错误:

“测试超时超过 5000 毫秒。如果这是一个长时间运行的测试,请使用 jest.setTimeout(newTimeout) 增加超时值。” 我不得不更改 Jest 为测试设置的超时值。如本评论所述,可以通过两种方式完成:

" 1. 向它添加第三个参数。即 it('runs slow', () => {...}, 10000) 2. 将 jest.setTimeout(10000); 写入名为 src/setupTests 的文件中。 js,如此处所述。”

最后我的测试看起来像这样:


  it('display error message', async () => {
    server.use(
      rest.get(getUrl('/recipes'), (req, res, ctx) =>
        res(ctx.status(500), ctx.json({ errorMessage: 'Test Error' }))
      )
    );

    render(<RecipeListWithQueryClient />);

    expect(
      await screen.findByText(/error/i, {}, { timeout: 10000 })
    ).toBeInTheDocument();
  }, 10000);

这里可以使用不同的异步方法,例如 waitFor 和 waitForElementToBeRemoved,它们都可以将 { timeout: 10000 } 对象作为参数。

这个解决方案对我有用,但是我想改进它,以避免测试花费太多时间。我只是还没弄清楚该怎么做。

于 2021-05-17T18:02:02.563 回答