使

使用 Jest 和 Cypress 测试您的 Amplify 应用程序

2025-06-07

使用 Jest 和 Cypress 测试您的 Amplify 应用程序

在本文中,我们将为使用 Amplify Console 部署的 Web 应用程序编写静态、单元、集成和端到端 (e2e) 测试,该应用程序使用 Amplify 生成的 AppSync GraphQL API 来查询、变异和订阅数据。

我们正在测试的应用程序可以在这里找到,带有测试的最终代码可以在这里找到。

介绍

在我们继续之前,如果您不确定不同类型的测试之间有什么区别,或者每种类型的含义,请阅读@kentcdodds这篇文章(老实说,即使您这样做了,也应该阅读它)。

静态测试不是通过执行代码来完成的,而是通过读取代码、解析代码并尝试查找其中的问题来完成的。我们将使用 TypeScript、ESLint 和 Prettier 进行静态测试。

单元测试确保各个代码单元(函数、组件、类……)针对给定的输入产生正确的输出(和效果)。我们将对应用的 React Reducer 进行单元测试,它是一个纯函数(确定性且无副作用)。

集成测试让我们确信不同的代码单元能够按照预期协同工作。我们将使用React 测试库测试我们的路由组件。

最后,端到端测试会像最终用户一样与我们的应用进行交互。
我们将构建代码,然后使用CypressCypress 测试库进行交互并运行断言。

静态测试

打字稿

我们正在测试的应用使用了 Next.js。从版本 9 开始,Next.js 即开即用地支持 TypeScript,无需任何配置(更多信息)。

如果您从头开始运行:npx create-next-app --example with-typescript

因此,我们只需用 TypeScript 编写代码并运行 TypeScript 编译器来验证每次推送之前没有错误。

为此,我们需要添加一个 git hook,它在每次推送之前运行 TypeScript 编译器,并在代码编译出现错误时阻止我们推送。

Husky使得添加和配置 git hooks 变得简单。

我们首先添加 husky 作为开发依赖项:



npm i -D husky # Or yarn add -D husky


Enter fullscreen mode Exit fullscreen mode

然后在 中package.json添加一个配置了 git hooks 的 Husky 部分



{
  "husky": {
    "pre-push": "tsc"
  }
}


Enter fullscreen mode Exit fullscreen mode

这就是 TypeScript 的全部,现在,每当我们尝试推送无法编译的代码时,Husky 都会抛出异常并阻止我们这样做。

ESLint

2019 年开始,ESLint 已获得 TypeScript 的全面支持。TSLint即将被弃用,取而代之的是 ESLint,因此在新项目中使用 ESLint 可能是更明智的选择。

为此,我们首先使用 JavaScript 设置 ESLint,然后添加 TypeScript 支持

首先安装 eslint、eslint react 插件和 typescript 解析器



yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react # npm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react


Enter fullscreen mode Exit fullscreen mode

然后使用.eslintrc.js项目根目录中的配置文件初始化 eslint:



module.exports = {
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended"
  ],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
      modules: true
    },
    ecmaVersion: 2018,
    sourceType: "module"
  },
  parser: "@typescript-eslint/parser",
  plugins: ["react"],
  rules: {
    // I usually turn off these rules out of personal, feel free to delete the rules section in your project
    "@typescript-eslint/explicit-function-return-type": "off",
    "react/prop-types": "off"
  }
};


Enter fullscreen mode Exit fullscreen mode

要检查代码,请运行:



# Lint all ts or tsx files in src/ and src/{any}/
yarn eslint src/**/*.ts*  src/*.ts* # or $(npm bin)/eslint src/**/*.ts*  src/*.ts


Enter fullscreen mode Exit fullscreen mode

或者添加脚本来package.json运行命令:



{
  "scripts": {
    "lint": "eslint src/**/*.ts*  src/*.ts*"
  }
}


Enter fullscreen mode Exit fullscreen mode

由于该项目使用 Amplify Codegen,我们需要告诉 eslint 忽略使用.eslintignore文件由 cli 发出的生成代码。

正如名称所示,它的行为类似于.gitignoreeslint。



# Path to code generated by Amplify
src/graphql/
src/API.ts


Enter fullscreen mode Exit fullscreen mode

最后,为你的编辑器下载并安装一个 eslint 插件,这样在输入代码时就能看到警告和错误信息。如果你使用的是 VSCode,请点击此处获取插件链接

Prettier

使用 Prettier 是一件轻而易举的事,它也算是一种静态测试,因为它可以解析代码并在无法解析时抛出错误。



yarn add -D prettier # npm i -D prettier


Enter fullscreen mode Exit fullscreen mode

然后将更漂亮的内容添加到您的代码编辑器中,再也不用考虑格式化了。

最终的 git hooks 变成package.json



{
  "husky": {
    "pre-commit": "prettier --write \"src/*.ts\" \"src/**/*.ts*\"",
    "pre-push": "tsc && yarn lint"
  }
}


Enter fullscreen mode Exit fullscreen mode

请注意,这会在您的整个代码库上进行 lint 并运行得更漂亮,如果您正在处理大型代码库,那么使用lint-staged仅验证更改的文件可能是一个好主意。

使用 TypeScript 和 ESLint 设置 Jest

有两种方法可以设置 Jest 和 TypeScript:您可以使用 Babel 在运行代码之前剥离类型(无需类型检查),或者使用 TypeScript 编译器在运行代码之前编译。官方文档似乎建议用户使用 Babel,而且 Jest 使用 Babel 比 ts-jest 使用 tsc 更快。因此,我们将使用 Babel 并使用预提交钩子来处理类型检查。

1. 使用 Babel 设置 Jest

跑步



yarn add -D jest @types/jest babel-jest @babel/core @babel/preset-env @babel/preset-react


Enter fullscreen mode Exit fullscreen mode

babel.config.js在根目录中创建一个文件并在其中添加:



module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        targets: {
          node: "current"
        }
      }
    ],
    "@babel/preset-react"
  ]
};


Enter fullscreen mode Exit fullscreen mode

2. 为 Babel 添加 TypeScript 支持



yarn add -D @babel/preset-typescript


Enter fullscreen mode Exit fullscreen mode

以及babel.config.js



- "@babel/preset-react"
+ "@babel/preset-react",
+ "@babel/preset-typescript"


Enter fullscreen mode Exit fullscreen mode

3. 使用 Jest 配置 ESLint

安装eslint-plugin-jest



yarn add -D eslint-plugin-jest # npm i -D eslint-plugin-jest


Enter fullscreen mode Exit fullscreen mode

并在 .eslintrc.js 文件中,添加 jest 插件和 jest 全局变量(describe、test、expect...):



module.exports = {
  env: {
    browser: true,
-    es6: true
+    es6: true,
+    "jest/globals": true
  },
-  plugins: ["@typescript-eslint", "react"],
+  plugins: ["@typescript-eslint", "react", "jest"],
}



Enter fullscreen mode Exit fullscreen mode

此时,Jest 应该使用 ESLint 和 TypeScript 正确设置。

运行测试包括在__tests__目录中添加 TS 文件并执行:




yarn jest # $(npm bin)/jest # npx jest



Enter fullscreen mode Exit fullscreen mode

单元测试

单元测试确保函数在某些输入下能够按照预期运行。

纯函数非常适合单元测试。

我们使用的 React Reducer 包含应用程序的主要逻辑,它是一个纯函数。对于每个给定的状态和动作组合,该函数都会返回一个新的状态。

Jest 是一个注重简单性的测试框架,可用于单元和集成测试。

测试 Reducer

测试 Reducer 函数包括使用不同的操作和状态调用 Reducer 并对输出运行断言。

我们将每个测试定义为以下类型:



type ReducerTest = {
  state: State;
  action: Action;
  assertions: (newState: State, state: State, action: Action) => void;
};


Enter fullscreen mode Exit fullscreen mode

例如,确保添加频道有效的简单测试如下所示:



import cases from "jest-in-case";

const reducerTest = {
  name: "Can append channel to empty state"
  state: getInitialState(),
  action: {
    type: "append-channels",
    payload: { items: [createChannel()], nextToken: null }
  },
  assertions: (newState, state, action) => {
    expect(newState.channels.items.length).toEqual(1);
  }
};

const tests = [reducerTest];

const runTest = reducerTest => {
  const newState = reducer(reducerTest.state, reducerTest.action);
  reducerTest.assertions(newState, reducerTest.state, reducerTest.action);
};

cases("works", runTest, tests);


Enter fullscreen mode Exit fullscreen mode

添加测试包括将项目添加到测试数组中。

jest-in-case是一个“用于创建相同测试变体的 Jest 实用程序”

您可以在此处找到更多测试

集成测试

这些将使我们确信我们的组件能够按预期协同工作。我们将对路由组件进行测试和运行断言。

但在此之前我们需要设置模拟。

选择要模拟的内容

模拟包括用具有相同 API 但效果不同的另一个代码单元替换一个代码单元。

例如,假设我们想要模拟来自的 API 对象@aws-amplify/api

该应用程序仅使用graphqlAPI 的方法和 graphqlOperation 方法,因此模拟它就足够了。

@aws-amplify/api是一个 npm 模块,为了模拟它,我们需要__mocks__在根目录中添加一个文件夹,并在其中创建一个@aws-amplify名为的文件夹和文件api.ts

__mocks__/@aws-amplify/api.ts看起来像这样:



const API = {
  graphql: operation => {
    if (isSubscription(operation)) return Observable;
    else return Promise;
  }
};
export const graphqlOperation = (query, variables) => ({ query, variables });
export default API;


Enter fullscreen mode Exit fullscreen mode

但是在这种低层次上进行模拟将使测试正确的行为变得更加困难。

例如,如果在挂载时,组件调用API.graphql3 次,一次用于突变,一次用于查询,一次用于订阅。

为了测试它,我们需要使 API.graphql 模拟相对复杂,它需要在每次调用时解析查询并根据它返回适当类型的数据)所以我们将更上一层楼。

我们不会模拟@aws-amplify/api模块,而是模拟我们的模型。

此应用中的模型是 UI 与远程 API 交互的唯一接口。组件不允许使用@aws-amplify/api,而是使用与 API 通信的模型,在需要时处理数据,然后使用 Observable 或 Promise 将数据返回给调用者。

例如,为了获得列出所有渠道的承诺,我们可以写如下内容:

在 App.tsx 中



import * as React from "react";
import { models } from "./models/ModelsContext";

const App = () => {
  const [channels, setChannels] = React.useState({ items: [], nextToken: "" });
  React.useEffect(() => {
    models.Channels.getChannels().then(chans => {
      setChannels(c => ({
        items: [...c.items, ...chans.items],
        nextToken: chans.nextToken
      }));
    });
  }, []);
  const loadMore = () => {
    models.Channels.getChannels(channels.nextToken).then(chans => {
      setChannels(c => ({
        items: [...c.items, ...chans.items],
        nextToken: chans.nextToken
      }));
    });
  };
  return (
    <Some>
      <ReactTree
        onEndReached={() => {
          loadMore();
        }}
      >
        {channels.items.map(chan => (
          <ChannelCard channel={chan} />
        ))}
      </ReactTree>
    </Some>
  );
};


Enter fullscreen mode Exit fullscreen mode

在 models/Channels.tsx 中:



import API, { graphqlOperation } from "@aws-amplify/api";
import { queryToGetChannels } from "path/to/generated/graphql/queries";

const EMPTY_CHANNELS = { items: [], nextToken: "" }

export const getChannels = async () => {
  try {
    const channels = await API.graphql(graphqlOperation(queryToGetChannels));
    if (isValidChannelsData(channels))){
      return channels;
    }
    return EMPTY_CHANNELS;
  } catch (err) {
    return EMPTY_CHANNELS;
  }
};


Enter fullscreen mode Exit fullscreen mode

如果您不确定该交易是什么nextToken以及如何使用它,请参阅我之前关于使用 AWS Amplify
进行分页和排序的博客文章

如果 Amplify API 按预期工作,模拟模型将使我们相信应用程序可以正常工作,这对于集成测试来说已经足够了。

除了模型之外,依赖于 JSDOM 中不可用的浏览器功能的依赖项也应该被模拟。这类依赖项只有两个:react-intersection-observer一个依赖于 IntersectionObserver API,next/router另一个在 JSDOM 环境中返回空路由器。模拟前者应该很简单,因为它是一个简单的 React hook;模拟后者更简单,因为它只是一个 useContext 调用。

从 next/router模拟useRouter

如果你看一下useRouter 的代码,它只是React.useContext对路由器上下文的调用:



import { RouterContext } from "next-server/dist/lib/router-context";
export function useRouter() {
  return React.useContext(RouterContext);
}


Enter fullscreen mode Exit fullscreen mode

因此,我们不需要使用 Jest 模拟 useRouter,我们只需要将测试包装在新的 RouterContext.Provider 中,并且子组件将在每次测试中注入一个自定义路由器。



import { RouterContext } from "next-server/dist/lib/router-context";

render(
  <RouterContext.Provider
    value={{
      pathname: "/",
      push: jest.fn()
      //...
    }}
  >
    <App />
  </RouterContext.Provider>
);


Enter fullscreen mode Exit fullscreen mode

现在,应用程序在调用时将可以访问上面上下文提供的对象useRouter()

如果您以前没有使用过 Context,请务必阅读有关 Context 的 React 文档。

模拟react-intersection-observer

使用 Jest 模拟 npm 依赖非常简单:

  1. __mocks__在根目录中创建一个名为的文件夹。
  2. 添加一个名为 的文件react-intersection-observer.ts
  3. 它内部模拟模块的行为。

__mocks__/react-intersection-observer.ts



import * as React from "react";

export const useInView = jest.fn().mockImplementation(() => {
  return [React.useRef(), true];
});

export default {
  useInView
};


Enter fullscreen mode Exit fullscreen mode

jest.fn()是一个很好的 Jest 实用函数,用于创建可定制、可覆盖和可检查的模拟函数。

使用 useInView 的组件的示例测试如下所示:

组件:



import * as React from "react";
// When running this code in our tests, the import will be replaced with the code from __mocks/react-intersection-observer
import { useInView } from "react-intersection-observer";

export const Comp = () => {
  const [ref, inView] = useInView();
  return <div ref={ref}>{inView ? "Visible" : "Hidden"}</div>;
};


Enter fullscreen mode Exit fullscreen mode

测试:



import * as React from "react";
import { render } from "@testing-library/react";

import { useInView } from "../__mocks__/react-intersection-observer";
import { Comp } from "../components/Comp";

describe("Comp with use-in-view", () => {
  test("is displayed when inView true", () => {
    useInView.mockImplementation(() => {
      return [React.useRef(), true];
    });
    const { getByText } = render(<ComponentUsingInView />);
    getByText("Visible");
  });
  test("is hidden when inView false", () => {
    useInView.mockImplementation(() => {
      return [React.useRef(), false];
    });
    const { getByText } = render(<ComponentUsingInView />);
    getByText("Hidden");
  });
});


Enter fullscreen mode Exit fullscreen mode

@testing-library/react 点击此处了解更多信息

使用模拟模型测试应用程序

使用 Jest 模拟用户模块类似于模拟节点模块:

  1. __mocks__在您想要模拟的文件或目录的同一目录中创建一个名为 的文件夹。
  2. 在里面__mocks__添加一个与您想要模拟的文件同名的文件。
  3. 如果测试代码也使用模拟,则在运行测试之前通过调用以下命令进行设置jest.mock('./path/to/module')

与 Amplify API 交互的模型将返回 Promise(用于查询和变异)或 Observable(用于订阅)。

一旦 Promise 解析成功,或者可观察对象发出值,我们就会更新状态以反映变化。例如,getChannels解析成功后,应用代码会触发状态更新以显示新数据。

应用程序的 UI 在这些 Promise/Observable 解析/发出之前和之后看起来往往会有所不同。如果能够在解析/发出之前和之后运行断言就好了。



const { getAllByLabelText } = render(<Component />);
const allChannels = getAllByLabelText("channel");

// before getChannels resolves
expect(allChannels.length).toEqual(0);
// Do something here 👇 to resolve getChannels
// ...
// after getChannels resolves
expect(allChannels.length).toEqual(4);


Enter fullscreen mode Exit fullscreen mode

为此,我们需要为每个测试或测试套件提供自定义模拟,以满足这些承诺和可观察对象的需求。

承诺返回方法

模型的模拟是简单的 Jest 模拟函数。正确的实现和数据则留给测试套件来提供。

例如,getChannels模拟是一行代码src/models/__mocks__/Channels.ts



export const getChannels = jest.fn();


Enter fullscreen mode Exit fullscreen mode

__tests__/channels.test.tsx渲染我们的组件之前,我们将为这个模拟提供正确的行为:



import * as React from "react";
import { act } from "react-dom/test-utils";
import { render } from "@testing-library/react";
import { getChannels } from "../src/models/__mocks__/Channels.ts";

const dataBank = {
  channels: () => [
    {
      id: "channel-1"
      //,...otherFields
    }
  ]
};
type TestUtils = ReturnType<typeof render>

const selectors = {
  channelList: (testUtils:TestUtils) => testUtils.getAllByTestId("Channel Card");
}

describe("channels", () => {
  let resolveGetChannels;
  getChannels.mockImplementation(() => {
    return new Promise(resolve => {
      // Now a test can resolve getChannels whenever and with any data
      resolveGetChannels = resolve;
    });
  });
  test("works", async () => {
    const testUtils = render(<Channels />);

    // Expect getChannels to be called ( it's called on mount )
    expect(getChannels.toBeCalled());

    // And getChannels hasn't resolved yet because we haven't called resolveGetChannels
    expect(() => {
      selectors.channelList(testUtils)
    }).toThrow();

    // Wait for promise to resolve and ui to update
    await act(async () => {
      resolveGetChannels(dataBank.channels());
    });

    // Make sure that channels are visible
    expect(selectors.channelList(testUtils).length).toEqual(1);
  });
});


Enter fullscreen mode Exit fullscreen mode

如果你不确定它act是什么,或者它在做什么,那么请阅读@threepointone 的精彩解释

可观察的返回方法

像承诺返回模型一样,我们首先将方法定义为:



export const onCreateChannel = jest.fn();


Enter fullscreen mode Exit fullscreen mode

我们将在测试套件中定义正确的实现。

对于 GraphQL 订阅,AWS Amplify API 库会返回一个 Observable 对象。该库使用zen-observable来创建可观察对象。但这只是一个实现细节,我们可以使用 RxJS 或任何其他 Observable 实现来模拟返回类型。

如果你还没有使用过 RxJS 或 Observables,你只需要将 Observable 视为一个 Promise,

  1. 可以解决多次。
  2. 可以使用subscribe代替 来收听then

这只是基于本文所需内容的简化。
如需更深入的解释,请参阅Andre Staltz的《你一直错过的响应式编程入门》



// Creating a promise that is invoked after {ms}ms
const delay = ms => {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  });
};
// Creating an observable that emits every {ms}ms
const interval = ms => {
  return new Observable(observer => {
    setInterval(() => observer.next(), ms);
  });
};

// Getting the resolved value from a promise
// Fires only once
delay(10).then(value => {});

// Getting the resolved value from a observable
// Fires indefinitely
interval(1000).subscribe(value => {});


Enter fullscreen mode Exit fullscreen mode

在我们的测试中,我们将要劫持observer.next方法,并将其提供给单独的测试,以便在需要时调用:



import * as React from "react";
import { act } from "react-dom/test-utils";
import { Observable } from "rxjs"; // or 'zen-observable'
import { render } from "@testing-library/react";

import { onCreateChannel } from "../src/models/__mocks__/Channels.ts";

const dataBank = {
  channel: () => ({
    id: "channel-1"
    //,...otherFields
  })
};

describe("channels", () => {
  let emitOnCreateChannel;
  onCreateChannel.mockImplementation(() => {
    return new Observable(observer => {
      // Now a test can emit new channels whenever and with any data
      emitOnCreateChannel = v => observer.next(v);
    });
  });
  test("works", () => {
    const { getAllByTestId } = render(<Channels />);
    // Expect onCreateChannel to be called ( it's called on mount )
    expect(onCreateChannel.toBeCalled());
    // The list of channels should be empty before data is fetched with models, 
    expect(() => {
      getAllByTestId("Channel Card");
    }).toThrow();

    // Wait for the observer to emit and ui to update
    act(() => {
      emitOnCreateChannel(dataBank.channel());
    });

    // Make sure that the added channel is visible
    expect(getAllByTestId("Channel Card").length).toEqual(1);
  });
});


Enter fullscreen mode Exit fullscreen mode

您可以在此处看到更多此类测试

端到端测试

我们将使用Cypress进行 E2E 测试,因为它具有相对较好的开发体验(在我看来),但如果您需要在多个浏览器中运行测试或者不特别喜欢使用 Cypress,那么testcafe可能更适合您。

Cypress 运行测试

准备测试环境

我们将使用 Amplify cli 的内置mock方法模拟整个 Amplify API

确保您拥有的 amplify 版本> = 1.11.0(带有amplify --version)并且您安装了 java(api mock 使用的 DynamoDBLocal 是一个 java 应用程序)。

在初始化的放大项目中运行:amplify mock api

这将在您的本地计算机上创建应用程序云环境的副本,并更新应用程序配置以指向它(通过更新src/aws-exports.js)。

运行此命令后,我们可以启动应用程序(npm run dev),它将以与以前完全相同的方式工作,但将连接到本地数据库而不是远程数据库。

安装支持 TypeScript 的 Cypress 非常简单:

  1. 安装 Cypress 并初始化它:yarn add -D cypress && yarn cypress --init
  2. 安装add-typescript-to-cypressyarn add -D @bahmutov/add-typescript-to-cypress
  3. 👍将 TypeScript 测试添加到cypress/integration/目录

添加测试

E2E 测试应该像用户浏览应用程序一样运行。
我们将@testing-library/cypress在 Cypress 和 Jest 测试之间共享代码(UI 选择器)。以下是 Cypress 测试套件的示例,该套件确保用户可以读取和编辑其个人资料信息,如下所示:




// Note that the code for our selectors is almost identical to the selectors used with Jest
// This is thanks to @testing-library/react & @testing-library/cypress 
// Profile selectors
const profile = {
  form: (cypress = cy) => cypress.getByLabelText("Profile Form"),
  submit: () => cy.getByLabelText("Profile Form Submit Button"),
  username: () => cy.getByLabelText("Username"),
  bio: () => cy.getByLabelText("Bio"),
  url: () => cy.getByLabelText("Url")
};

// Header selectors
const header = {
  root: () => cy.getByLabelText("Header Navigation").should("be.visible"),
  me: () =>
    header
      .root()
      .within(() => cy.getByText("My Profile"))
      .should("be.visible"),
  channels: () =>
    header
      .root()
      .within(() => cy.getByText("Channels"))
      .should("be.visible")
};

describe("My Profile", () => {
  beforeEach(() => {
    cy.visit(BASE_URL);
  });
  afterEach(() => {
    // For video to better capture what happened
    cy.wait(1000);
  });
  it("Can visit profile and set information", () => {
    const user = {
      name: "Test username",
      url: "https://test-url.test",
      bio: "Bio Test @ Test BIO"
    };
    header.me().click();
    cy.location("href").should("contain", "/me");
    profile.username().type(`${user.name}{enter}`);
    cy.title().should("contain", `${user.name}'s Profile`);
    profile.bio().type(`${user.bio}{enter}`);
    profile.url().type(`${user.url}`);
    profile.submit().click();

    // Make sure data is persisted between sessions
    cy.reload();
    profile.username().should("contain.value", user.name);
    profile.bio().should("contain.value", user.bio);
    profile.url().should("contain.value", user.url);
  });
});


Enter fullscreen mode Exit fullscreen mode

您可以在此处查看更多 TypeScript Cypress 测试。

添加测试脚本package.json

回顾一下用于运行不同测试的脚本:



{
"scripts": {
"test:static": "yarn lint && yarn tsc",
"test:jest": "yarn jest",
"test:e2e": "(amplify mock api &) && wait-on http-get://localhost:20002 && kill-port 3000 && (yarn dev &) && wait-on http-get://localhost:3000 && cypress run --env PORT=3000",
"test:e2e:dev": "(amplify mock api &) && wait-on http-get://localhost:20002 && kill-port 3000 && (yarn dev &) && wait-on http-get://localhost:3000 && cypress open --env PORT=3000",
"test": "yarn test:static && yarn test:jest"
},
"hooks": {
"pre-commit": "prettier --write \"src/.ts\" \"src//.ts*\"",
"pre-push": "yarn test"
}
}
Enter fullscreen mode Exit fullscreen mode




每次提交时从 Amplify 控制台运行测试

我们只需要告诉 Amplify Console 在每次提交部署之前运行我们的测试。

为此,我们将添加以下内容amplify.yml



version: 0.1
frontend:
phases:
preBuild:
commands:
- yarn install
build:
commands:
# This makes sure that the commit is not deployed if the tests fail.
- yarn run test && yarn run build
artifacts:
baseDirectory: build
files:
- "/*"
cache:
paths:
- node_modules//*

Enter fullscreen mode Exit fullscreen mode




总结

我们已经向使用 Amplify API 的现有聊天应用程序添加了静态、单元、集成和端到端测试,并在提交和推送代码之前以及在使用 Amplify Console 部署之前在云端使用 git hooks 运行它们。

如果您想深入了解,请确保克隆代码库并在本地试验 Jest 和 Cypress 测试。

干杯!

文章来源:https://dev.to/rakannimer/testing-your-amplify-application-with-jest-and-cypress-1g0i
PREV
寻找黑客马拉松的 5 个最佳地点!🧑‍💻
NEXT
学习 React 之前先了解一下 JS 中的运算符和对象解构