【译】Cypress指南: 端到端测试入门

·  阅读 4136

端到端测试可能很慢而且很无聊。Cypress改变了我们的测试方式。在此教程中,了解如何使用Cypress测试你的应用程序。

要求

要想继续接下来的学习,你需要在电脑上安装好nodejs,以及对新版本es特性和语法有一定的了解最好。

Cypress是什么?什么是端到端测试?

端到端测试或UI测试是测试Web应用程序的多种方法之一。

端到端测试应该通过测试所谓的用户流来检查Web应用程序是否按预期工作。

端到端测试重要吗?是的。但是没有人喜欢端到端测试。它们编写起来可能很慢,麻烦,成本很高。

但是,测试又使你满怀信心。你是否希望将有bug的产品给到你的用户?

Cypress:一个Javascript端到端测试框架。这将使您的生活更轻松。

免责声明

在纯粹主义者对我大喊之前:我知道端到端测试,UI测试,集成测试等之间的微妙界限。

对于读者你来说,测试技术非常的模糊,我甚至不太好描述。如果你是第一次使用JavaScript测试,我建议阅读初学者Jest教程:JavaScript测试Jest入门,以获取有关单元测试和术语的介绍。

当你阅读完上面的入门文章之后,就可以返回这里来继续看了。

初始化项目

首先创建一个新文件夹, cypress-tutorial,然后进入到该文件夹中,初始化一个新的JavaScript项目:

   mkdir cypress-tutorial && cd $_
   npm init -y
复制代码

在此文件夹中,创建两个新文件。 index.html中的HTML文档:

<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <title>Cypress tutorial for beginners</title>
 </head>
 <body>
   <main>
     <form>
       <div>
         <label for="name">Name</label>
         <input type="name" required name="name" id="name" />
       </div>
       <div>
         <label for="email">Email</label>
         <input type="email" required name="email" id="email" />
       </div>
       <div>
         <label for="message">Your message</label>
         <textarea id="message" name="message" required></textarea>
       </div>
       <div>
         <button type="submit">SEND</button>
       </div>
     </form>
   </main>
 </body>
 <script src="form.js"></script>
</html>
复制代码

这是一个HTML表单,其中包含大量input和textarea元素。接下来,在form.js中创建一个具有处理表单提交的最小逻辑的JavaScript文件:

const form = document.forms[0];

form.addEventListener("submit", event => {
 event.preventDefault();
});
复制代码

请注意,我不会添加样式来使事情保持简单。通过这个简单的项目,我们准备安装 Cypress。

安装 Cypress

在项目文件夹中,运行一下命令:

npm i cypress --save-dev
复制代码

稍等一下(需要下载二进制文件),然后运行:

node_modules/.bin/cypress open
复制代码

Cypress 将首次启动,并且一堆新文件夹将出现在您的项目中。您可以删除示例文件夹,但请稍候片刻,因为有一些不错的示例。

现在关闭窗口,然后转到下一部分。

开始项目

要在本地计算机上提供项目,请确保安装了较新版本的Node.js,然后运行:

npx serve
复制代码

执行之后,会启动一个服务,在 http://localhost:5000/,打开链接应该可以看到如下表单:

serve 是一个不错的NPM开发包。现在该写我们的第一个测试了!

编写你的第一个测试

在 cypress/integration/form.spec.js 中创建一个新文件,并编写你的第一个块:

describe("Form test", () => {
  //
});
复制代码

describe 是一种 Cypress 方法(从Mocha借来的),用于包含一个或多个相关测试。每次您开始为功能编写新的测试套件时,都将其包装在 describe 块中。

如您所见,它带有两个参数:用于描述测试套件的字符串和用于包装实际测试的回调函数。

接下来,我们将遇到另一个称为 it 的函数,它是实际的测试块:

describe("Form test", () => {
  it("Can fill the form", () => {
    //
  });
});
复制代码

如果你熟悉Jest,可能知道里面可以包含 it 或者 test。但是 Cypress 并不是这样的,只能包含 it。

现在开始冒烟测试。在代码块中这样写:

describe("Form test", () => {
  it("Can fill the form", () => {
    cy.visit("/");
    cy.get("form");
  });
});
复制代码

cy是 Cypress 本身,而 visit 是 Cypress 用于浏览到给定路径的方法。

get 是一种在页面中选择元素的方法。使用此代码,我们告诉 Cypress “去获取页面中的表单”。

一分钟内,我们将看到 Cypress 斯的实际应用,但首先要进行一些配置!

配置Cypress

为了简化流程,我们先配置下 Cypress 。 首先,打开package.json并创建一个名为e2e的脚本,该脚本指向Cypress二进制文件:

  "scripts": {
    "e2e": "cypress open"
  },
复制代码

接下来打开cypress.json并配置基本URL:

{
  "baseUrl": "http://localhost:5000"
}
复制代码

使用此选项,我们告诉 Cypress访问我们的开发URL。 (服务的默认端口为5000)。 现在我们准备开始你的第一个测试!

运行测试

在一个终端中运行以下命令:

npx serve
复制代码

再另外一个终端中运行:

npm run e2e
复制代码

你应该看到 Cypress 打开浏览器并浏览该页面:

这是你的第一个测试,通过! Visit 和 get 都是 Cypress 命令,它们也充当隐式断言,也就是说,如果元素在页面中,则Cypress将通过测试。

现在,让我们继续扩展测试以查看用户是否可以填写表单:

describe("Form test", () => {
  it("Can fill the form", () => {
    cy.visit("/");
    cy.get("form");

    cy.get('input[name="name"]').type("Molly");
  });
});
复制代码

这是另一个 Cypress 命令:type,毫无疑问,这是将内容输入到第一个 input 中。还要注意CSS选择器以获取输入元素。

同时,我们还要添加另一个命令:should。此命令创建一个断言,并用于例如检查输入是否正在按预期更新其状态:

describe("Form test", () => {
  it("Can fill the form", () => {
    cy.visit("/");
    cy.get("form");

    cy.get('input[name="name"]')
      .type("Molly")
      .should("have.value", "Molly");
  });
});
复制代码

注意have.value。如果您不熟悉此概念,可以在此处了解有关断言的更多信息。

进行了最小限度的测试之后,让我们进入下一节。

更多的测试和提交表单

要继续我们的测试,我们可以检查电子邮件输入:

  it("Can fill the form", () => {
    cy.visit("/");
    cy.get("form");

    cy.get('input[name="name"]')
      .type("Molly")
      .should("have.value", "Molly");

    cy.get('input[name="email"]')
      .type("molly@dev.dev")
      .should("have.value", "molly@dev.dev");
  });
});
复制代码

我们也可以输入文本区域:

describe("Form test", () => {
  it("Can fill the form", () => {
    cy.visit("/");
    cy.get("form");

    cy.get('input[name="name"]')
      .type("Molly")
      .should("have.value", "Molly");

    cy.get('input[name="email"]')
      .type("molly@dev.dev")
      .should("have.value", "molly@dev.dev");

    cy.get("textarea")
      .type("Mind you if I ask some silly question?")
      .should("have.value", "Mind you if I ask some silly question?");
  });
});
复制代码

如果你让 Cypress 保持打开,则测试应观察你的更改并自动运行:

舒服!趁热打铁,让我们通过 sumbit 来测试表单的提交。

describe("Form test", () => {
  it("Can fill the form", () => {
    cy.visit("/");
    cy.get("form");

    cy.get('input[name="name"]')
      .type("Molly")
      .should("have.value", "Molly");

    cy.get('input[name="email"]')
      .type("molly@dev.dev")
      .should("have.value", "molly@dev.dev");

    cy.get("textarea")
      .type("Mind you if I ask some silly question?")
      .should("have.value", "Mind you if I ask some silly question?");

    cy.get("form").submit();
  });
});
复制代码

测试应保持通过,没有任何问题。你可以注意到的一件事是这些自我描述的命令:type,submit。这是简单的英语。

现在,让我们在下一部分中进行XHR请求测试。

使用 Cypress 斯处理XHR请求

Cypress 还可以拦截AJAX请求。这种方法称为存根(Stubbing)。

在开发中工作时,存根很方便,您可以选择对AJAX请求返回假响应。

为了演示此功能,让我们在测试中添加一段新代码:

  it("Can fill the form", () => {
    cy.visit("/");
    cy.get("form");
    
    // omitted for brevity

    cy.server();
    cy.route({
      url: "/users/**",
      method: "POST",
      response: { status: "Saved", code: 201 }
    });

    cy.get("form").submit();
  });
});
复制代码

此处cy.server启动了一个“虚拟”服务器,而cy.route用于配置伪造的API端点。

现在,让我们添加另一个测试以检查问题:用户提交表单后,我们要测试假API是否正在响应。为什么这样?

存根非常有用,因为我们可以在开发中完全绕过真实的API。让我们用cy.contains扩展测试:

  it("Can fill the form", () => {
    cy.visit("/");
    cy.get("form");
    
    // omitted for brevity

    cy.server();
    cy.route({
      url: "/users/**",
      method: "POST",
      response: { status: "Form saved!", code: 201 }
    });

    cy.get("form").submit();

    cy.contains("Form saved!");
  });
});
复制代码

由于没有将表单发送到API的逻辑,因此测试预计会失败。在下一节中,我们将设法让通过测试。

将表单数据发送到API

这个部分中,请包含。在写本文的适合, Cypress 还不能拦截 fetch 请求

我们将改为使用XMLHttpRequest。(查看此内容进行介绍

打开form.js并实现逻辑:

const form = document.forms[0];

form.addEventListener("submit", event => {
  event.preventDefault();
  new FormData(form);
});

document.addEventListener("formdata", event => {
  const body = Object.fromEntries(event.formData.entries());
  const jsonBody = JSON.stringify(body);
  const request = new XMLHttpRequest();
  request.open("POST", "https://jsonplaceholder.typicode.com/users/");
  request.send(jsonBody);
});
复制代码

在此代码段中,我使用了 formdata 事件。当我们调用 new FormData 时,会触发此事件。

在事件侦听器中,我们使用fromEntries(ECMAScript 2019)构建对象。我们将数据发送到API。

为了使测试通过,我们还需要从API返回响应并将其保存到文档中。为此,我们可以侦听XMLHttpRequest的onload事件:

// omit
document.addEventListener("formdata", event => {
  const body = Object.fromEntries(event.formData.entries());
  const jsonBody = JSON.stringify(body);
  const request = new XMLHttpRequest();
  request.open("POST", "https://jsonplaceholder.typicode.com/users/");
  request.send(jsonBody);
  // get the response
  request.onload = function() {
    const jsonResponse = JSON.parse(this.response);
  };
});
复制代码

最后,我们可以危险地(为了使事情简单)将响应保存在页面中(请永远不要在生产环境的代码库中这样做):

// omit
  request.onload = function() {
    const jsonResponse = JSON.parse(this.response);
    document.body.innerHTML += `Response from the server: ${jsonResponse.status}`;
  };
复制代码

现在该看测试通过了!

Cypress 处理XHR请求:通过测试

概括一下,这是 cypress/integration/form.spec.js 中的完整测试:

describe("Form test", () => {
  it("Can fill the form", () => {
    cy.visit("/");
    cy.get("form");

    cy.get('input[name="name"]')
      .type("Molly")
      .should("have.value", "Molly");

    cy.get('input[name="email"]')
      .type("molly@dev.dev")
      .should("have.value", "molly@dev.dev");

    cy.get("textarea")
      .type("Mind you if I ask some silly question?")
      .should("have.value", "Mind you if I ask some silly question?");

    cy.server();
    cy.route({
      url: "/users/**",
      method: "POST",
      response: { status: "Form saved!", code: 201 }
    });

    cy.get("form").submit();

    cy.contains("Form saved!");
  });
});
复制代码

这是form.js的完整代码


form.addEventListener("submit", event => {
  event.preventDefault();
  new FormData(form);
});

document.addEventListener("formdata", event => {
  const body = Object.fromEntries(event.formData.entries());
  const jsonBody = JSON.stringify(body);
  const request = new XMLHttpRequest();
  request.open("POST", "https://jsonplaceholder.typicode.com/users/");
  request.send(jsonBody);
  // get the response
  request.onload = function() {
    const jsonResponse = JSON.parse(this.response);
    document.body.innerHTML += `Response from the server: ${jsonResponse.status}`;
  };
});
复制代码

要记住的一件事是,真正的API可能不会返回与假存根相同的数据结构。

在开发真实应用程序时,你确实需要使测试适应真实系统。

但是现在我们很好,如果你让 Cypress 保持打开状态,您应该已经看到测试通过:

你可以在左上方看到一个路由部分,并在测试输出中看到XHR存根,这表明赛普拉斯已拦截POST请求。

这是 Cypress 的最佳功能之一,不包括数十个可供使用的命令和断言。

通过存根,我们可以结束本教程。优秀!

结论

我希望您从本教程中学到了新知识,并将这些概念应用于下一个项目!测试很重要!

端到端测试应该不难:Cypress 使它非常简单且令人愉悦。Cypress 的团队确实做到了。

另外,文档是最直接的:Cypress Docs 包含了最佳实践和示例。

谢谢阅读!

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改