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持續集成的設置