使用 V6 模拟 AWS Amplify API 和存储进行单元测试

问题描述 投票:0回答:1

我有一个利用 Amplify 在 AWS 中运行的 Typescript/React 应用程序。 我的应用程序利用 Amplify API (GraphQL) 和 Amplify Storage 来与 Amazon 服务配合使用。

在 Amplify V5 中,我能够为相关 API 调用设置 Jest 函数,这样我就可以安全地运行单元测试。

setupTests.ts


import {API, Storage} from "aws-amplify";

/** Establish API mocking before all tests. */
beforeAll(() => {
  URL.revokeObjectURL = jest.fn();
  //Window.prototype.scroll = jest.fn();
  window.HTMLElement.prototype.scroll = jest.fn();
  window.HTMLDivElement.prototype.scroll = jest.fn();

  jest.mock('aws-amplify');
  API.graphql    = jest.fn();
  Storage.get    = jest.fn();
  Storage.copy   = jest.fn();
  Storage.remove = jest.fn();
});

我现在正在将 amplify 从 V5 升级到 V6。 API 发生了变化。 而不是

import {API, Storage} from "aws-amplify";
然后在这些对象上运行函数,函数将直接导入。

import {generateClient} from 'aws-amplify/api'
import {getUrl, downloadData, copy, remove, uploadData} from 'aws-amplify/storage';

我尝试了一些不同的方法来模拟 setupTests.ts 中的generateClient,但没有任何效果。

jest.mock('aws-amplify');
jest.mock('aws-amplify/api');
jest.mock('aws-amplify/storage');
  jest.mock('aws-amplify/api',
            () => { return { generateClient: () => { graphql: jest.fn() } };
  });
jest.mock('generateClient', () => { graphql: jest.fn(); });
  jest.mock('aws-amplify/api', () => {
    return { generateClient: () => { graphql: jest.fn() } };
  });
import * as API from 'aws-amplify/api';
  
beforeAll(() => {  
  API.generateClient = jest.fn();
  const generateClient = jest.mocked(API).generateClient;
  const generateClient = API.generateClient;
});
jest.mocked(generateClient).mockImplementation(() => ({graphql: jest.fn()}));
  jest.mock('aws-amplify/auth');
  jest.mock('getUrl', () => jest.fn());
  jest.mock('downloadData', () => jest.fn());
  jest.mock('uploadData', () => jest.fn());
  jest.mock('copy', () => jest.fn());
  jest.mock('remove', () => jest.fn());
  // @ts-ignore
  generateClient.mockImplementation(() => ({graphql: jest.fn()}));

  // @ts-ignore
  getUrl.mockImplementation(() => {});
  // @ts-ignore
  downloadData.mockImplementation(() => {});
  // @ts-ignore
  uploadData.mockImplementation(() => {});
  // @ts-ignore
  copy.mockImplementation(() => {});
  // @ts-ignore
  remove.mockImplementation(() => {});

测试时

expect(client.graphql).not.toHaveBeenCalled();
其中
client = generateClient();
和稍后在相同的
beforeAll
方法中或单独的测试文件中。我不断收到错误,指出
client.graphQL
是实际函数而不是模拟函数,在
*.mockImplementation()
示例中,错误是关于该函数不可用,因为代码尚未被模拟。

TL/DR: 在 Amplify V6 中,使用直接方法和生成器导出,如何将测试设置为仅使用 Jest Mock 函数来代替生产代码中的实际调用以进行单元测试?


更新:

如果我放

jest.mock('aws-amplify/api', () => ({
   generateClient: jest.fn(() => { graphql: jest.fn() }),
}));

//@ts-ignore
when(generateClient).calledWith().mockReturnValue({ graphql: jest.fn() });

在我的测试课中

describe(
之前,它成功地嘲笑了
generateClient()
client.graphql(

然而,使用 V5,我能够在 setupTests.ts 中设置这些模拟,然后它们可以在任何需要它们的测试文件中使用,而无需重复大量模拟代码,这要归功于
beforeAll(

上面的代码在

beforeAll(
中不起作用,所以我如何在一个地方安全地存储和设置模拟代码,这样我就不会复制一堆代码来到处设置模拟?


更新2 根据请求,最少的测试代码:

import {generateClient} from "aws-amplify/api";

jest.mock('aws-amplify/api');
const client = generateClient();

describe('App', () => {

  test('mocks Amplify correctly', () =>
  {
    console.log(`generateClient: ${generateClient}`);
    expect(jest.isMockFunction(generateClient)).toBeTruthy();
    expect(jest.isMockFunction(client)).toBeFalsy();

    console.log(`client: ${client}`);

    expect(client).toHaveProperty('graphql');
    expect(jest.isMockFunction(client.graphql)).toBeTruthy()
    expect(client.graphql).not.toHaveBeenCalled();
  });
});

这就是我一直用来验证我是否正确构建了预期的 Mock 对象的方法。
我有一些辅助文件和其他测试,它们使用

when()
告诉模拟对象返回预设的测试数据。

像这样:

test('Documents still display when getDocuments returns an error.',
       async () =>
{
   //setup mocking, with forced error
   when(client.graphql)
     .calledWith(expect.objectContaining({query: queries.listDocumentDetails} ))
     .mockRejectedValue(errorDocList);
 
   const { store } = renderPage(DASHBOARD_PATH, <Dashboard />, state);

   //check page renders
   expect(screen.getByText(RecentDocumentsTitle)).toBeInTheDocument();

   //check for error message
   const msg = `Failed to GET DocumentList: ${errorDocList.errors[0].message}`;
   const errorMsg = buildErrorAlert(msg);
   await waitFor(() => {
     expect(store.getState().alertMessage).toEqual(errorMsg);
   });

   const doc = errorDocList.data.listDocumentDetails.items[1]!;

   expect(screen.getByText(doc.eng_title)).toBeInTheDocument();
   expect(screen.getByText(doc.bc_title)).toBeInTheDocument();
   expect(screen.getByText(doc.ak_title)).toBeInTheDocument();
};
typescript unit-testing jestjs aws-amplify aws-amplify-sdk-js
1个回答
0
投票

我找到了我的问题。

解决方案是手动模拟。 文档说在模拟模块中的代码时,在

__mocks__
旁边创建一个
node_modules
文件夹。这对我的项目不起作用。解决方案是将
__mocks__
文件夹放在我的项目的
src
目录的根目录下。

© www.soinside.com 2019 - 2024. All rights reserved.