github持续集成的设置
Lately I've added continuous integration to my blog using Puppeteer for end to end testing. My main goal was to allow automatic dependency updates using Dependabot. In this guide I'll show you how to create such a pipeline yourself.
最近,我使用Puppeteer在博客中添加了持续集成,以进行端到端测试。 我的主要目标是允许使用Dependabot自动更新依赖项。 在本指南中,我将向您展示如何自己创建这样的管道。
As my CI platform, I chose Github Actions, as it is super easy to work with. It also integrates beautifully with any Github repository you already have. The whole thing only took roughly two days of intermittent work, and I think the results are quite awesome.
作为我的CI平台,我选择了Github Actions ,因为它非常易于使用。 它还可以与您已经拥有的任何Github存储库完美集成。 整个过程大约只花了两天的间歇时间,我认为结果非常棒。
I do want to give a shout-out to Nick Taylor, who published his article on the subject, and laid the ground work for my efforts here. I encourage you to read his article as well.
我确实要大声疾呼尼克·泰勒(Nick Taylor),他发表了有关该主题的文章 ,并为我在这里的努力奠定了基础。 我鼓励您也阅读他的文章。
My tech stack is quite different though. I chose puppeteer as my end-to-end framework for several reasons. The first is that it is written and maintained by the folks behind the Chrome dev tools, so I'm guaranteed a life-time of support (until Chrome dies out, which is not in the near future), and it is really easy to work with.
我的技术栈却大不相同。 由于多种原因,我选择puppeteer作为我的端到端框架。 首先是它是由Chrome开发者工具背后的人编写和维护的,因此可以保证我将终身提供支持(直到Chrome淘汰,这不会在不久的将来),而且确实很容易一起工作。
Another reason is that at home I'm working on a windows laptop with WSL (on which I'm running zshell with oh-my-zsh). Setting up cypress is quite a bit more difficult (although in our world nothing is impossible). Both reasons led me to choose puppeteer, and so far I'm not regretting it.
另一个原因是在家里,我正在使用WSL(在其上运行oh-my-zsh的zshell)在Windows笔记本电脑上工作。 设置柏树要困难得多(尽管在我们这个世界上没有什么是不可能的)。 这两个原因都促使我选择了操纵up,到目前为止,我并不后悔。
端到端测试 (End to end testing)
End to end (or E2E) tests are different from other types of automated tests. E2E tests simulate a real user, performing actions on the screen. This kind of test should help fill the blank space between "static" tests - such as unit tests, where you usually don't bootstrap the entire application - and component testing, which usually runs against a single component (or a service in a micro-service architecture).
端到端(或E2E)测试与其他类型的自动化测试不同。 E2E测试可模拟真实用户,并在屏幕上执行操作。 这种测试应该有助于填补“静态”测试(例如,单元测试(通常不引导整个应用程序)和组件测试)之间的空白,其中,组件测试通常针对单个组件(或微型服务)运行服务架构)。
By simulating user interaction you get to test the experience of using your application or service in the same way a regular user would experience it.
通过模拟用户交互,您可以测试普通用户体验应用程序或服务的体验。
The mantra that we try to follow is that it does not matter if your code performs perfectly if the button the user should press is hidden due to some CSS quirk. The end result is that the user will never get to feel the greatness of your code.
我们尝试遵循的口头禅是,由于某些CSS怪癖,如果用户应按下的按钮处于隐藏状态,则代码是否可以完美执行并不重要。 最终结果是用户将永远不会感觉到您的代码的伟大之处。
木偶手入门 (Getting started with puppeteer)
Puppeteer has a few configuration options that make it really awesome to use for writing and validating tests.
Puppeteer有几个配置选项,使编写和验证测试使用起来真的很棒。
Puppeteer tests can run in a "head-full" state. This means you can open a real browser window, navigate to the site being tested, and perform actions on the given page. This way you - the developers writing the tests - can see exactly what happens in the test, what buttons are being pressed and what the resulting UI looks like.
木偶测试可以在“满头”状态下运行。 这意味着您可以打开真实的浏览器窗口,导航到要测试的站点,然后在给定页面上执行操作。 这样,您-编写测试的开发人员-可以准确查看测试中发生的情况,按下的按钮以及生成的UI外观。
The opposite of "head-full" would be headless, where puppeteer does not open a browser window, making it ideal for CI pipelines.
与“ head-full”的相反将是无头的,其中操纵up的人不会打开浏览器窗口,因此非常适合CI管道。
Puppeteer is quite easy to work with, but you'll be surprised with the number of actions you can perform using an automated tool.
Puppeteer的操作非常简单,但是您会惊讶于使用自动化工具可以执行的操作数量。
We'll start with a basic scraper that prints the page title when we go to https://dorshinar.me. In order to run puppeteer tests, we must install it as a dependency:
我们将从基本的刮板开始,当我们转到https://dorshinar.me时,该刮板将打印页面标题。 为了运行操纵up的测试,我们必须将其安装为依赖项:
npm i puppeteer
Now, our basic scraper looks like this:
现在,我们的基本刮板如下所示:
const puppeteer = require("puppeteer");(async () => {const browser = await puppeteer.launch();const page = await browser.newPage();await page.goto("https://dorshinar.me");console.log(await page.title());await browser.close();
})();
What we do here is very simple: we open the browser with puppeteer.launch()
, create a new page with browser.newPage()
and navigate to this blog with page.goto()
, and then we print the title.
我们在这里做的是非常简单的:我们跟打开浏览器puppeteer.launch()
创建一个新的页面browser.newPage()
然后导航到该博客与page.goto()
然后我们打印标题。
There are a bunch of things we can do with the puppeteer API, such as:
我们可以使用puppeteer API做很多事情,例如:
Running code in the context of the page:
在页面上下文中运行代码:
(async () => {await page.evaluate(() => document.querySelector(".awesome-button").click());
})();
Clicking on elements in the screen using a CSS selector:
使用CSS选择器单击屏幕上的元素:
(async () => {await page.click(".awesome-button");
})();
Making use of the $
selector (jQuery style):
利用$
选择器(jQuery样式):
(async () => {await page.$(".awesome-button");
})();
Taking a screenshot:
截屏:
(async () => {await page.screenshot({ path: "screenshot.png" });
})();
There is a bunch more you can do with the puppeteer API, and I suggest you take a look at it before diving into writing tests. But the examples I've shown should give you a solid foundation to build from.
您可以使用puppeteer API做更多的事情,我建议您在开始编写测试之前先看一下它。 但是我展示的示例应该为您提供坚实的基础。
将木偶与Jest集成 (Integrating puppeteer with Jest)
jest is an awesome test runner and assertion library. From their docs:
笑话是一个了不起的测试运行程序和断言库。 从他们的文档:
Jest is a delightful JavaScript Testing Framework with a focus on simplicity.
Jest是一个令人愉悦JavaScript测试框架,专注于简单性。
Jest allows you to run tests, mock imports, and make complex assertions really easily. Jest is also bundled with create-react-app, so I use it often at work.
Jest允许您真正轻松地运行测试,模拟导入并进行复杂的断言。 Jest还与create-react-app捆绑在一起,因此我经常在工作中使用它。
编写您的第一个玩笑测试 (Writing your first Jest test)
Jest tests are super easy to write, and they might be familiar to those who know other testing frameworks (as Jest uses it
, test
, describe
and other familiar conventions).
Jest测试非常容易编写,并且对于熟悉其他测试框架的人可能很熟悉(因为Jest使用it
, test
, describe
和其他熟悉的约定)。
A basic test could look like:
基本测试可能类似于:
function subtract(a, b) {return a - b;
}it("subtracts 4 from 6 and returns 2", () => {expect(subtract(6, 4)).toBe(2);
});
You can also group multiple tests under one describe
, so you can run different describes or use it for convenient reporting:
您还可以将多个测试归为一个describe
,因此您可以运行不同的describe或将其用于方便的报告:
function divide(a, b) {if (b === 0) {throw new Error("Can't divide by zero!");}return a / b;
}describe("divide", () => {it("throws when dividing by zero", () => {expect(() => divide(6, 0)).toThrow();});it("returns 3 when dividing 6 by 3", () => {expect(divide(6, 3)).toBe(2);});
});
You can, of course, create much more complicated tests using mocks and other type of assertions (or expectations), but for now that's enough.
当然,您可以使用模拟和其他类型的断言(或期望)来创建更复杂的测试,但是到目前为止就足够了。
Running the tests is also very simple:
运行测试也非常简单:
jest
Jest will look for test files with any of the following popular naming conventions:
Jest将使用以下任何流行的命名约定查找测试文件:
Files with
.js
suffix in__tests__
folders.__tests__
文件夹中带有.js
后缀的文件。Files with
.test.js
suffix.带
.test.js
后缀的文件。Files with
.spec.js
suffix.带
.spec.js
后缀的文件。
玩笑木偶 (jest-puppeteer)
Now, we need to make puppeteer play nicely with jest. This isn't a particularly hard job to do, as there is a great package named jest-puppeteer that comes to our aid.
现在,我们需要使木偶戏与玩笑保持良好的配合。 这并不是一件特别困难的事情,因为有一个名为jest-puppeteer的出色软件包可以帮助我们。
First, we must install it as a dependency:
首先,我们必须将其安装为依赖项:
npm i jest-puppeteer
And now we must extend our jest configuration. If you don't have one yet, there are a number of ways to do it. I'll go with a config file. Create a file named jest.config.js
in the root of your project:
现在,我们必须扩展我们的笑话配置。 如果您还没有,那么有很多方法可以做到。 我将使用一个配置文件。 在项目的根目录中创建一个名为jest.config.js
的文件:
touch jest.config.js
In the file we must tell jest to use jest-puppeteer
's preset, so add the following code to the file:
在文件中,我们必须告诉jest使用jest-puppeteer
的预设,因此将以下代码添加到文件中:
module.exports = {preset: "jest-puppeteer"// The rest of your file...
};
You may specify a special launch configuration in a jest-puppeteer.config.js
file, and jest-puppeteer will pass this configuration to puppeteer.launch()
. For example:
您可以在jest-puppeteer.config.js
文件中指定特殊的启动配置,并且jest-puppeteer会将此配置传递给puppeteer.launch()
。 例如:
module.exports = {launch: {headless: process.env.CI === "true",ignoreDefaultArgs: ["--disable-extensions"],args: ["--no-sandbox"],executablePath: "chrome.exe"}
};
jest-puppeteer
will take care of opening a new browser and a new page and store them on the global scope. So in your tests you can simply use the globally available browser
and page
objects.
jest-puppeteer
将负责打开新的浏览器和新的页面,并将它们存储在全局范围内。 因此,在测试中,您可以简单地使用全局可用的browser
和page
对象。
Another great feature we can use is the ability of jest-puppeteer to run your server during your tests, and kill it afterwards, with the server
key:
我们可以使用的另一个出色功能是jest-puppeteer可以在测试期间运行服务器,然后使用server
密钥将其杀死:
module.exports = {launch: {},server: {command: "npm run serve",port: 9000,launchTimeout: 180000}
};
Now jest-puppeteer will run npm run serve
, with a timeout of 180 seconds (3 minutes), and listen on port 9000 to see when it will be up. Once the server starts the tests will run.
现在jest-puppeteer将运行npm run serve
,超时时间为180秒(3分钟),并在端口9000上监听以查看何时启动。 服务器启动后,测试将运行。
You can now write a full test suite using jest and puppeteer. The only thing left is creating a CI pipeline, for which we'll use GitHub actions.
您现在可以使用jest和puppeteer编写完整的测试套件。 剩下的唯一事情就是创建一个CI管道,我们将使用GitHub操作。
You can add a script to your package.json
file to execute your tests:
您可以将脚本添加到package.json
文件中以执行测试:
{"scripts": {"test:e2e": "jest"}
}
Github行动要点 (Github Actions in a gist)
Recently, Github released a big new feature called Actions. Basically, actions allow you to create workflows using plain yaml syntax, and run them on dedicated virtual machines.
最近,Github发布了一项名为Actions的重要新功能。 基本上,操作允许您使用简单的yaml语法创建工作流,并在专用虚拟机上运行它们。
In your workflow you can do pretty much anything you want, from basic npm ci && npm build && npm run test
to more complicated stuff.
从基本的npm ci && npm build && npm run test
到更复杂的工作,您都可以在工作流中做几乎所有您想做的事情。
I'll show you how to configure a basic workflow running your puppeteer test suite, and prevent merging if your tests don't pass.
我将向您展示如何配置运行puppeteer测试套件的基本工作流程,并在测试未通过的情况下防止合并。
The easiest way to start is to click on the Actions
tab in your github repo. If you haven't configured any action before, you'll see a list of previously configured workflows, from which you can choose one with some predefined configuration.
最简单的开始方法是单击github存储库中的“ Actions
选项卡。 如果您之前未配置任何操作,则将看到以前配置的工作流列表,您可以从中选择具有一些预定义配置的工作流。
For our case, choosing the predefined Node.js action is good enough. The generated yaml looks like this:
对于我们的情况,选择预定义的Node.js操作就足够了。 生成的yaml如下所示:
name: Node CIon: [push]jobs:build:runs-on: ubuntu-lateststrategy:matrix:node-version: [8.x, 10.x, 12.x]steps:- uses: actions/checkout@v1- name: Use Node.js ${{ matrix.node-version }}uses: actions/setup-node@v1with:node-version: ${{ matrix.node-version }}- name: npm install, build, and testrun: |npm cinpm run build --if-presentnpm testenv:CI: true
In the file you can configure the workflow name, jobs to run, and when to run the workflow. You can run your workflow on every push, on new pull requests, or as a recurring event.
在文件中,您可以配置工作流名称,要运行的作业以及运行时间。 您可以在每次推送,新的拉取请求或重复发生的事件上运行您的工作流。
Jobs in a workflow run in parallel by default, but can be configured to run in sequence. In the above workflow, there is one job named build
.
默认情况下,工作流中的作业并行运行,但可以配置为按顺序运行。 在上述工作流程中,有一个名为build
作业。
You can also choose the OS on which your workflow will run (by default you can use Windows Server 2019, Ubuntu 18.04, Ubuntu 16.04 and macOS Catalina 10.15 - at the time of publishing) with the runs-on
key.
您也可以选择在其工作流运行(默认情况下,你可以使用Windows Server 2019的,Ubuntu 18.04,Ubuntu的16.04和MacOS卡塔利娜10.15 -在出版时间)操作系统与runs-on
键。
The strategy
key can help us run our tests on a matrix of node versions. In this case we have the latest versions of the latest LTS majors - 8.x
, 10.x
and 12.x
. If you are interested in that you can leave it as is, or simply remove it and use any specific version you want.
strategy
密钥可以帮助我们在节点版本矩阵上运行测试。 在这种情况下,我们具有最新的LTS专业的最新版本8.x
, 10.x
和12.x
如果您对此感兴趣,可以将其保留不变,也可以将其删除并使用所需的任何特定版本。
The most interesting configuration option is the steps
. With it we define what actually goes on in our pipeline.
最有趣的配置选项是steps
。 通过它,我们定义了管道中实际发生的事情。
Each step represents an action you can perform, such as checking out code from the repo, setting up your node version, installing dependencies, running tests, uploading artifacts (to be used later or downloaded) and many more.
每个步骤都代表您可以执行的操作,例如从存储库中签出代码,设置节点版本,安装依赖项,运行测试,上传工件(稍后使用或下载)等等。
You can find a very extensive list of readily available actions in the Actions Marketplace.
您可以在Actions Marketplace中找到非常广泛的随时可用的动作列表。
The basic configuration will install dependencies, build our project and run our tests. If you need more (for example if you want to serve your application for e2e tests) you may alter it to your liking. Once done, commit your changes and you are good to go.
基本配置将安装依赖项,构建我们的项目并运行我们的测试。 如果您需要更多服务(例如,如果要为e2e测试提供服务),则可以根据自己的喜好进行更改。 完成后,提交您的更改,一切顺利。
强制检查在合并之前通过 (Forcing checks to pass before merge)
The only thing left for us is to make sure no code can be merged before our workflow passes successfully. For that, go to your repo's settings and click on Branches:
我们剩下的唯一事情就是确保在我们的工作流成功通过之前,不能合并任何代码。 为此,请转到您的仓库的设置,然后单击“分支”:
We need to set a Branch protection rule so that malicious code (or at least code that doesn't pass our tests) won't be merged. Click on Add rule, and under Branch name pattern put your protected branch (master, dev or whichever one you choose). Make sure Require status checks to pass before merging is checked, and you'll be able to choose which checks must pass:
我们需要设置分支保护规则,以使恶意代码(或至少没有通过测试的代码)不会被合并。 点击添加规则 ,然后在分支名称模式下放置受保护的分支(主,开发或您选择的任何一个)。 确保选中“ 需要状态检查才能通过合并” ,然后您可以选择必须通过哪些检查:
Click on Save changes below, and you're good to go!
点击下面的保存更改,一切顺利!
Thank you for reading!This article was previously published on my blog: dorshinar.me, If you want to read more content, you can check my blog as it would mean a lot to me.
谢谢您的阅读!本文先前发表在我的博客上: dorshinar.me ,如果您想内容,可以查看我的博客,因为这对我来说意义重大。
翻译自: https://www.freecodecamp.org/news/continuous-integration-with-github-actions-and-puppeteer/
github持续集成的设置