You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by gi...@apache.org on 2022/01/20 09:47:16 UTC

[dolphinscheduler-website] branch asf-site updated: Automated deployment: 7da7a0adea82c68bbeddb5774999f705ac27fe22

This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler-website.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new 29907ce  Automated deployment: 7da7a0adea82c68bbeddb5774999f705ac27fe22
29907ce is described below

commit 29907ce029350370e09194d7e8cd415ddc7f40b1
Author: github-actions[bot] <gi...@users.noreply.github.com>
AuthorDate: Thu Jan 20 09:43:26 2022 +0000

    Automated deployment: 7da7a0adea82c68bbeddb5774999f705ac27fe22
---
 ...ent.md.2eb2fd9.js => development.md.627e13d.js} |   2 +-
 en-us/development/api-standard.html                |   4 +-
 en-us/development/architecture-design.html         |   4 +-
 .../backend/mechanism/global-parameter.html        |   4 +-
 en-us/development/backend/mechanism/overview.html  |   4 +-
 .../development/backend/mechanism/task/switch.html |   4 +-
 en-us/development/backend/spi/alert.html           |   4 +-
 en-us/development/backend/spi/datasource.html      |   4 +-
 en-us/development/backend/spi/registry.html        |   4 +-
 en-us/development/backend/spi/task.html            |   4 +-
 .../development/development-environment-setup.html |   4 +-
 en-us/development/e2e-test.html                    | 186 +++++++++++++++++++++
 en-us/development/e2e-test.json                    |   6 +
 en-us/development/frontend-development.html        |   4 +-
 en-us/development/have-questions.html              |   4 +-
 img/e2e-test/Dlocal.png                            | Bin 0 -> 90609 bytes
 img/e2e-test/E2E_Cases.png                         | Bin 0 -> 30362 bytes
 img/e2e-test/MP4.png                               | Bin 0 -> 259242 bytes
 img/e2e-test/SecurityPage.png                      | Bin 0 -> 101787 bytes
 img/e2e-test/timeout.png                           | Bin 0 -> 225366 bytes
 zh-cn/development/api-standard.html                |   4 +-
 zh-cn/development/architecture-design.html         |   4 +-
 .../backend/mechanism/global-parameter.html        |   4 +-
 zh-cn/development/backend/mechanism/overview.html  |   4 +-
 .../development/backend/mechanism/task/switch.html |   4 +-
 zh-cn/development/backend/spi/alert.html           |   4 +-
 zh-cn/development/backend/spi/datasource.html      |   4 +-
 zh-cn/development/backend/spi/registry.html        |   4 +-
 zh-cn/development/backend/spi/task.html            |   4 +-
 .../development/development-environment-setup.html |   4 +-
 zh-cn/development/e2e-test.html                    | 186 +++++++++++++++++++++
 zh-cn/development/e2e-test.json                    |   6 +
 zh-cn/development/frontend-development.html        |   4 +-
 zh-cn/development/have-questions.html              |   4 +-
 34 files changed, 433 insertions(+), 49 deletions(-)

diff --git a/build/development.md.2eb2fd9.js b/build/development.md.627e13d.js
similarity index 52%
rename from build/development.md.2eb2fd9.js
rename to build/development.md.627e13d.js
index c82cb95..29581ef 100644
--- a/build/development.md.2eb2fd9.js
+++ b/build/development.md.627e13d.js
@@ -1 +1 @@
-webpackJsonp([7],{1:function(e,t){e.exports=React},3:function(e,t){e.exports=ReactDOM},427:function(e,t,n){"use strict";function l(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new Type [...]
\ No newline at end of file
+webpackJsonp([7],{1:function(e,t){e.exports=React},3:function(e,t){e.exports=ReactDOM},427:function(e,t,n){"use strict";function l(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new Type [...]
\ No newline at end of file
diff --git a/en-us/development/api-standard.html b/en-us/development/api-standard.html
index afc0aaa..0ae7138 100644
--- a/en-us/development/api-standard.html
+++ b/en-us/development/api-standard.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <p>A standardized and unified API is the cornerstone of project design.The API of DolphinScheduler follows the REST ful standard. REST ful is currently the most popular Internet software architecture. It has a clear structure, conforms to standards, is easy to understand and extend.</p>
 <p>This article uses the DolphinScheduler API as an example to explain how to construct a Restful API.</p>
 <h2>1. URI design</h2>
@@ -101,7 +101,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/architecture-design.html b/en-us/development/architecture-design.html
index 1483e97..43cc952 100644
--- a/en-us/development/architecture-design.html
+++ b/en-us/development/architecture-design.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <p>Before explaining the architecture of the schedule system, let us first understand the common nouns of the schedule system.</p>
 <h3>1.Noun Interpretation</h3>
 <p><strong>DAG:</strong> Full name Directed Acyclic Graph,referred to as DAG。Tasks in the workflow are assembled in the form of directed acyclic graphs, which are topologically traversed from nodes with zero indegrees of ingress until there are no successor nodes. For example, the following picture:</p>
@@ -291,7 +291,7 @@ Public <span class="hljs-class"><span class="hljs-keyword">class</span> <span cl
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/backend/mechanism/global-parameter.html b/en-us/development/backend/mechanism/global-parameter.html
index 4e50b2e..d906cab 100644
--- a/en-us/development/backend/mechanism/global-parameter.html
+++ b/en-us/development/backend/mechanism/global-parameter.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <p>After the user defines the parameter with the direction OUT, it is saved in the localParam of the task.</p>
 <h2>Usage of parameters</h2>
 <p>Getting the direct predecessor node <code>preTasks</code> of the current <code>taskInstance</code> to be created from the DAG, get the <code>varPool</code> of <code>preTasks</code>, merge this varPool (List) into one <code>varPool</code>, and in the merging process, if parameters with the same parameter name are found, they will be handled according to the following logics:</p>
@@ -61,7 +61,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/backend/mechanism/overview.html b/en-us/development/backend/mechanism/overview.html
index 0a9e399..adde201 100644
--- a/en-us/development/backend/mechanism/overview.html
+++ b/en-us/development/backend/mechanism/overview.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <!-- TODO Since the side menu does not support multiple levels, add new page to keep all sub page here -->
 <ul>
 <li><a href="global-parameter.md">Global Parameter</a></li>
@@ -21,7 +21,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/backend/mechanism/task/switch.html b/en-us/development/backend/mechanism/task/switch.html
index c979a9f..8451fdf 100644
--- a/en-us/development/backend/mechanism/task/switch.html
+++ b/en-us/development/backend/mechanism/task/switch.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <p>Switch task workflow step as follows</p>
 <ul>
 <li>User-defined expressions and branch information are stored in <code>taskParams</code> in <code>taskdefinition</code>. When the switch is executed, it will be formatted as <code>SwitchParameters</code></li>
@@ -23,7 +23,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/backend/spi/alert.html b/en-us/development/backend/spi/alert.html
index d6ca559..1b7e9f9 100644
--- a/en-us/development/backend/spi/alert.html
+++ b/en-us/development/backend/spi/alert.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <h4>DolphinScheduler SPI Design</h4>
 <p>DolphinScheduler is undergoing a microkernel + plug-in architecture change. All core capabilities such as tasks, resource storage, registration centers, etc. will be designed as extension points. We hope to use SPI to improve DolphinScheduler’s own flexibility and friendliness (extended sex).</p>
 <p>For alarm-related codes, please refer to the <code>dolphinscheduler-alert-api</code> module. This module defines the extension interface of the alarm plug-in and some basic codes. When we need to realize the plug-inization of related functions, it is recommended to read the code of this block first. Of course, it is recommended that you read the document. This will reduce a lot of time, but the document There is a certain degree of lag. When the document is missing, it is recommended  [...]
@@ -74,7 +74,7 @@ This package is a plug-in parameter definition. Our front-end uses the from-crea
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/backend/spi/datasource.html b/en-us/development/backend/spi/datasource.html
index 5001198..fe98155 100644
--- a/en-us/development/backend/spi/datasource.html
+++ b/en-us/development/backend/spi/datasource.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <h4>How do I use data sources?</h4>
 <p>The data source center supports POSTGRESQL, HIVE/IMPALA, SPARK, CLICKHOUSE, SQLSERVER data sources by default.</p>
 <p>If you are using MySQL or ORACLE data source, you need to place the corresponding driver package in the lib directory</p>
@@ -34,7 +34,7 @@ org.apache.dolphinscheduler.plugin.datasource.api.client.CommonDataSourceClient<
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/backend/spi/registry.html b/en-us/development/backend/spi/registry.html
index 4149276..053d746 100644
--- a/en-us/development/backend/spi/registry.html
+++ b/en-us/development/backend/spi/registry.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <h4>how to use?</h4>
 <p>Make the following configuration (take zookeeper as an example)</p>
 <ul>
@@ -33,7 +33,7 @@ All configuration information prefixes need to be +registry, such as <a href="ht
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/backend/spi/task.html b/en-us/development/backend/spi/task.html
index 1c69a71..b40dc34 100644
--- a/en-us/development/backend/spi/task.html
+++ b/en-us/development/backend/spi/task.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <h4>How to develop task plugins?</h4>
 <p>org.apache.dolphinscheduler.spi.task.TaskChannel</p>
 <p>The plug-in can implement the above interface. It mainly includes creating tasks (task initialization, task running, etc.) and task cancellation. If it is a yarn task, you need to implement org.apache.dolphinscheduler.plugin.task.api.AbstractYarnTask.</p>
@@ -23,7 +23,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/development-environment-setup.html b/en-us/development/development-environment-setup.html
index d7e77b3..61ee309 100644
--- a/en-us/development/development-environment-setup.html
+++ b/en-us/development/development-environment-setup.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <h2>Software Requests</h2>
 <p>Before setting up the DolphinScheduler development environment, please make sure you have installed the software as below:</p>
 <ul>
@@ -150,7 +150,7 @@ npm run start
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/e2e-test.html b/en-us/development/e2e-test.html
new file mode 100644
index 0000000..d67ac71
--- /dev/null
+++ b/en-us/development/e2e-test.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+  <meta name="keywords" content="e2e-test">
+  <meta name="description" content="e2e-test">
+  <title>e2e-test</title>
+  <link rel="shortcut icon" href="/img/favicon.ico">
+  <link rel="stylesheet" href="/build/vendor.23870e5.css">
+</head>
+<body>
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+<h2>I. Preparatory knowledge</h2>
+<h3>1. The difference between E2E Test and Unit Test</h3>
+<p>E2E, which stands for &quot;End to End&quot;, can be translated as &quot;end-to-end&quot; testing. It imitates the user, starting from a certain entry point and progressively performing actions until a certain job is completed. And unit tests are different, the latter usually requires testing parameters, types and parameter values, the number of arguments, the return value, throw an error, and so on, the purpose is to ensure that a specific function to finishing the work is stable and [...]
+<p>In contrast, E2E test does not emphasize so much the need to cover all usage scenarios, it focuses on whether a complete chain of operations can be completed. For the web front-end, it is also concerned with the layout of the interface and whether the content information meets expectations.</p>
+<p>For example, E2E test of the login page is concerned with whether the user is able to enter and log in normally, and whether the error message is correctly displayed if the login fails. It is not a major concern whether input that is not legal is processed.</p>
+<h3>2. Selenium test framework</h3>
+<p><a href="(https://www.selenium.dev/)">Selenium</a> is an open source testing tool for executing automated tests on a web browser. The framework uses WebDriver to transform Web Service commands into browser native calls through the browser's native components to complete operations. In simple words, it simulates the browser and makes selection operations on the elements of the page.</p>
+<p>A WebDriver is an API and protocol which defines a language-neutral interface for controlling the behavior of a web browser.  Every browser has a specific WebDriver implementation, called a driver. The driver is the component responsible for delegating to the browser and handling the communication with Selenium and the browser.</p>
+<p>The Selenium framework links all these components together through a user-facing interface that allows transparent work with different browser backends, enabling cross-browser and cross-platform automation.</p>
+<h2>II. E2E Test</h2>
+<h3>1. E2E-Pages</h3>
+<p>DolphinScheduler's E2E tests are deployed using docker-compose. The current tests are in standalone mode and are mainly used to check some basic functions such as &quot;add, delete, change and check&quot;. For further cluster validation, such as collaboration between services or communication mechanisms between services, refer to <code>deploy/docker/docker-compose.yml</code> for configuration.</p>
+<p>For E2E test (the front-end part),  the <a href="https://www.selenium.dev/documentation/guidelines/page_object_models/">page model</a> form is used, mainly to create a corresponding model for each page. The following is an example of a login page.</p>
+<pre><code class="language-java"><span class="hljs-keyword">package</span> org.apache.dolphinscheduler.e2e.pages;
+
+<span class="hljs-keyword">import</span> org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
+<span class="hljs-keyword">import</span> org.apache.dolphinscheduler.e2e.pages.security.TenantPage;
+
+<span class="hljs-keyword">import</span> org.openqa.selenium.WebElement;
+<span class="hljs-keyword">import</span> org.openqa.selenium.remote.RemoteWebDriver;
+<span class="hljs-keyword">import</span> org.openqa.selenium.support.FindBy;
+<span class="hljs-keyword">import</span> org.openqa.selenium.support.ui.ExpectedConditions;
+<span class="hljs-keyword">import</span> org.openqa.selenium.support.ui.WebDriverWait;
+
+<span class="hljs-keyword">import</span> lombok.Getter;
+<span class="hljs-keyword">import</span> lombok.SneakyThrows;
+
+<span class="hljs-meta">@Getter</span>
+<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginPage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NavBarPage</span> </span>{
+    <span class="hljs-meta">@FindBy(id = &quot;inputUsername&quot;)</span>
+    <span class="hljs-keyword">private</span> WebElement inputUsername;
+
+    <span class="hljs-meta">@FindBy(id = &quot;inputPassword&quot;)</span>
+    <span class="hljs-keyword">private</span> WebElement inputPassword;
+
+    <span class="hljs-meta">@FindBy(id = &quot;btnLogin&quot;)</span>
+    <span class="hljs-keyword">private</span> WebElement buttonLogin;
+
+    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">LoginPage</span><span class="hljs-params">(RemoteWebDriver driver)</span> </span>{
+        <span class="hljs-keyword">super</span>(driver);
+    }
+
+    <span class="hljs-meta">@SneakyThrows</span>
+    <span class="hljs-function"><span class="hljs-keyword">public</span> TenantPage <span class="hljs-title">login</span><span class="hljs-params">(String username, String password)</span> </span>{
+        inputUsername().sendKeys(username);
+        inputPassword().sendKeys(password);
+        buttonLogin().click();
+
+        <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">10</span>)
+            .until(ExpectedConditions.urlContains(<span class="hljs-string">&quot;/#/security&quot;</span>));
+
+        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> TenantPage(driver);
+    }
+}
+</code></pre>
+<p>During the test process, we only test the elements we need to focus on, not all elements of the page. So on the login page only the username, password and login button elements are declared. The FindBy interface is provided by the Selenium test framework to find the corresponding id or class in a Vue file.</p>
+<p>In addition, during the testing process, the elements are not manipulated directly. The general choice is to package the corresponding methods to achieve the effect of reuse. For example, if you want to log in, you input your username and password through the <code>public TenantPage login()</code> method to manipulate the elements you pass in to achieve the effect of logging in. That is, when the user finishes logging in, he or she jumps to the Security Centre (which goes to the Tenan [...]
+<p>The goToTab method is provided in SecurityPage to test the corresponding sidebar jumps, which include TenantPage, UserPage and WorkerGroupPge and QueuePage. These pages are implemented in the same way, to test that the form's input, add and delete buttons return the corresponding pages.</p>
+<pre><code class="language-java"> <span class="hljs-keyword">public</span> &lt;T extends SecurityPage.Tab&gt; <span class="hljs-function">T <span class="hljs-title">goToTab</span><span class="hljs-params">(Class&lt;T&gt; tab)</span> </span>{
+        <span class="hljs-keyword">if</span> (tab == TenantPage.class) {
+            WebElement menuTenantManageElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                    .until(ExpectedConditions.elementToBeClickable(menuTenantManage));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, menuTenantManageElement);
+            <span class="hljs-keyword">return</span> tab.cast(<span class="hljs-keyword">new</span> TenantPage(driver));
+        }
+        <span class="hljs-keyword">if</span> (tab == UserPage.class) {
+            WebElement menUserManageElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                    .until(ExpectedConditions.elementToBeClickable(menUserManage));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, menUserManageElement);
+            <span class="hljs-keyword">return</span> tab.cast(<span class="hljs-keyword">new</span> UserPage(driver));
+        }
+        <span class="hljs-keyword">if</span> (tab == WorkerGroupPage.class) {
+            WebElement menWorkerGroupManageElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                    .until(ExpectedConditions.elementToBeClickable(menWorkerGroupManage));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, menWorkerGroupManageElement);
+            <span class="hljs-keyword">return</span> tab.cast(<span class="hljs-keyword">new</span> WorkerGroupPage(driver));
+        }
+        <span class="hljs-keyword">if</span> (tab == QueuePage.class) {
+            menuQueueManage().click();
+            <span class="hljs-keyword">return</span> tab.cast(<span class="hljs-keyword">new</span> QueuePage(driver));
+        }
+        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnsupportedOperationException(<span class="hljs-string">&quot;Unknown tab: &quot;</span> + tab.getName());
+    }
+</code></pre>
+<p><img src="../../img/e2e-test/SecurityPage.png" alt="SecurityPage"></p>
+<p>For navigation bar options jumping, the goToNav method is provided in <code>org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java</code>. The currently supported pages are: ProjectPage, SecurityPage and ResourcePage.</p>
+<pre><code class="language-java">    <span class="hljs-keyword">public</span> &lt;T extends NavBarItem&gt; <span class="hljs-function">T <span class="hljs-title">goToNav</span><span class="hljs-params">(Class&lt;T&gt; nav)</span> </span>{
+        <span class="hljs-keyword">if</span> (nav == ProjectPage.class) {
+            WebElement projectTabElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                .until(ExpectedConditions.elementToBeClickable(projectTab));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, projectTabElement);
+            <span class="hljs-keyword">return</span> nav.cast(<span class="hljs-keyword">new</span> ProjectPage(driver));
+        }
+
+        <span class="hljs-keyword">if</span> (nav == SecurityPage.class) {
+            WebElement securityTabElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                .until(ExpectedConditions.elementToBeClickable(securityTab));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, securityTabElement);
+            <span class="hljs-keyword">return</span> nav.cast(<span class="hljs-keyword">new</span> SecurityPage(driver));
+        }
+
+        <span class="hljs-keyword">if</span> (nav == ResourcePage.class) {
+            WebElement resourceTabElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                .until(ExpectedConditions.elementToBeClickable(resourceTab));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, resourceTabElement);
+            <span class="hljs-keyword">return</span> nav.cast(<span class="hljs-keyword">new</span> ResourcePage(driver));
+        }
+
+        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnsupportedOperationException(<span class="hljs-string">&quot;Unknown nav bar&quot;</span>);
+    }
+</code></pre>
+<h3>E2E-Cases</h3>
+<p>Current E2E test cases supported include: File Management, Project Management, Queue Management, Tenant Management, User Management, Worker Group Management and Workflow Test.</p>
+<p><img src="../../img/e2e-test/E2E_Cases.png" alt="E2E_Cases"></p>
+<p>The following is an example of a tenant management test. As explained earlier, we use docker-compose for deployment, so for each test case, we need to import the corresponding file in the form of an annotation.</p>
+<p>The browser is loaded using the RemoteWebDriver provided with Selenium. Before each test case is started there is some preparation work that needs to be done. For example: logging in the user, jumping to the corresponding page (depending on the specific test case).</p>
+<pre><code class="language-java">    <span class="hljs-meta">@BeforeAll</span>
+    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span> </span>{
+        <span class="hljs-keyword">new</span> LoginPage(browser)
+                .login(<span class="hljs-string">&quot;admin&quot;</span>, <span class="hljs-string">&quot;dolphinscheduler123&quot;</span>) 
+                .goToNav(SecurityPage.class) 
+                .goToTab(TenantPage.class)
+        ;
+    }
+</code></pre>
+<p>When the preparation is complete, it is time for the formal test case writing. We use a form of @Order() annotation for modularity, to confirm the order of the tests. After the tests have been run, assertions are used to determine if the tests were successful, and if the assertion returns true, the tenant creation was successful. The following code can be used as a reference:</p>
+<pre><code class="language-java">    <span class="hljs-meta">@Test</span>
+    <span class="hljs-meta">@Order(10)</span>
+    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">testCreateTenant</span><span class="hljs-params">()</span> </span>{
+        <span class="hljs-keyword">final</span> TenantPage page = <span class="hljs-keyword">new</span> TenantPage(browser);
+        page.create(tenant);
+
+        await().untilAsserted(() -&gt; assertThat(page.tenantList())
+                .as(<span class="hljs-string">&quot;Tenant list should contain newly-created tenant&quot;</span>)
+                .extracting(WebElement::getText)
+                .anyMatch(it -&gt; it.contains(tenant)));
+    }
+</code></pre>
+<p>The rest are similar cases and can be understood by referring to the specific source code.</p>
+<p><a href="https://github.com/apache/dolphinscheduler/tree/dev/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases">https://github.com/apache/dolphinscheduler/tree/dev/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases</a></p>
+<h2>III. Supplements</h2>
+<p>When running E2E tests locally, the <code>-Dlocal=true</code> parameter can be configured to connect locally and facilitate changes to the UI.</p>
+<p><img src="../../img/e2e-test/Dlocal.png" alt="Dlocal"></p>
+<p>If a connection timeout occurs during a local run, increase the load time to a recommended 30 and above.</p>
+<p><img src="../../img/e2e-test/timeout.png" alt="timeout"></p>
+<p>The test run will be available as an MP4 file.</p>
+<p><img src="../../img/e2e-test/MP4.png" alt="MP4"></p>
+</div></section><footer class="footer-container"><div class="footer-body"><div><h3>About us</h3><h4>Do you need feedback? Please contact us through the following ways.</h4></div><div class="contact-container"><ul><li><a href="/en-us/community/development/subscribe.html"><img class="img-base" src="/img/emailgray.png"/><img class="img-change" src="/img/emailblue.png"/><p>Email List</p></a></li><li><a href="https://twitter.com/dolphinschedule"><img class="img-base" src="/img/twittergray.png [...]
+  <script src="//cdn.jsdelivr.net/npm/react@15.6.2/dist/react-with-addons.min.js"></script>
+  <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
+  <script>window.rootPath = '';</script>
+  <script src="/build/vendor.e29fe5d.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
+  <script>
+    var _hmt = _hmt || [];
+    (function() {
+      var hm = document.createElement("script");
+      hm.src = "https://hm.baidu.com/hm.js?4e7b4b400dd31fa015018a435c64d06f";
+      var s = document.getElementsByTagName("script")[0];
+      s.parentNode.insertBefore(hm, s);
+    })();
+  </script>
+  <!-- Global site tag (gtag.js) - Google Analytics -->
+  <script async src="https://www.googletagmanager.com/gtag/js?id=G-899J8PYKJZ"></script>
+  <script>
+    window.dataLayer = window.dataLayer || [];
+    function gtag(){dataLayer.push(arguments);}
+    gtag('js', new Date());
+
+    gtag('config', 'G-899J8PYKJZ');
+  </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/en-us/development/e2e-test.json b/en-us/development/e2e-test.json
new file mode 100644
index 0000000..ad35c9c
--- /dev/null
+++ b/en-us/development/e2e-test.json
@@ -0,0 +1,6 @@
+{
+  "filename": "e2e-test.md",
+  "__html": "<h1>DolphinScheduler E2E Automation Test</h1>\n<h2>I. Preparatory knowledge</h2>\n<h3>1. The difference between E2E Test and Unit Test</h3>\n<p>E2E, which stands for &quot;End to End&quot;, can be translated as &quot;end-to-end&quot; testing. It imitates the user, starting from a certain entry point and progressively performing actions until a certain job is completed. And unit tests are different, the latter usually requires testing parameters, types and parameter values, t [...]
+  "link": "/dist/en-us/development/e2e-test.html",
+  "meta": {}
+}
\ No newline at end of file
diff --git a/en-us/development/frontend-development.html b/en-us/development/frontend-development.html
index bf00fd4..fd202d5 100644
--- a/en-us/development/frontend-development.html
+++ b/en-us/development/frontend-development.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <h3>Technical selection</h3>
 <pre><code>Vue mvvm framework
 
@@ -515,7 +515,7 @@ Interface parameter transfer needs to be changed to the following way</p>
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/en-us/development/have-questions.html b/en-us/development/have-questions.html
index 2c36ccc..6ea06c5 100644
--- a/en-us/development/have-questions.html
+++ b/en-us/development/have-questions.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/en-us/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">中</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-lig [...]
 <h2>StackOverflow</h2>
 <p>For usage questions, it is recommended you use the StackOverflow tag <a href="https://stackoverflow.com/questions/tagged/apache-dolphinscheduler">apache-dolphinscheduler</a> as it is an active forum for DolphinScheduler users’ questions and answers.</p>
 <p>Some quick tips when using StackOverflow:</p>
@@ -74,7 +74,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/img/e2e-test/Dlocal.png b/img/e2e-test/Dlocal.png
new file mode 100644
index 0000000..2ba9efb
Binary files /dev/null and b/img/e2e-test/Dlocal.png differ
diff --git a/img/e2e-test/E2E_Cases.png b/img/e2e-test/E2E_Cases.png
new file mode 100644
index 0000000..1da2891
Binary files /dev/null and b/img/e2e-test/E2E_Cases.png differ
diff --git a/img/e2e-test/MP4.png b/img/e2e-test/MP4.png
new file mode 100644
index 0000000..fb194b4
Binary files /dev/null and b/img/e2e-test/MP4.png differ
diff --git a/img/e2e-test/SecurityPage.png b/img/e2e-test/SecurityPage.png
new file mode 100644
index 0000000..592af57
Binary files /dev/null and b/img/e2e-test/SecurityPage.png differ
diff --git a/img/e2e-test/timeout.png b/img/e2e-test/timeout.png
new file mode 100644
index 0000000..9a31a70
Binary files /dev/null and b/img/e2e-test/timeout.png differ
diff --git a/zh-cn/development/api-standard.html b/zh-cn/development/api-standard.html
index 84ff54b..5d08b7f 100644
--- a/zh-cn/development/api-standard.html
+++ b/zh-cn/development/api-standard.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <p>规范统一的 API 是项目设计的基石。DolphinScheduler 的 API 遵循 REST ful 标准,REST ful 是目前最流行的一种互联网软件架构,它结构清晰,符合标准,易于理解,扩展方便。</p>
 <p>本文以 DolphinScheduler 项目的接口为样例,讲解如何构造具有 Restful 风格的 API。</p>
 <h2>1. URI 设计</h2>
@@ -100,7 +100,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/architecture-design.html b/zh-cn/development/architecture-design.html
index effe111..ac0e5b3 100644
--- a/zh-cn/development/architecture-design.html
+++ b/zh-cn/development/architecture-design.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <p>在对调度系统架构说明之前,我们先来认识一下调度系统常用的名词</p>
 <h3>1.名词解释</h3>
 <p><strong>DAG:</strong> 全称Directed Acyclic Graph,简称DAG。工作流中的Task任务以有向无环图的形式组装起来,从入度为零的节点进行拓扑遍历,直到无后继节点为止。举例如下图:</p>
@@ -299,7 +299,7 @@ ZooKeeper Master容错完成之后则重新由DolphinScheduler中Scheduler线程
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/backend/mechanism/global-parameter.html b/zh-cn/development/backend/mechanism/global-parameter.html
index 2833f58..989310c 100644
--- a/zh-cn/development/backend/mechanism/global-parameter.html
+++ b/zh-cn/development/backend/mechanism/global-parameter.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <p>用户在定义方向为 OUT 的参数后,会保存在 task 的 localParam 中。</p>
 <h2>参数的使用</h2>
 <p>从 DAG 中获取当前需要创建的 taskInstance 的直接前置节点 preTasks,获取 preTasks 的 varPool,将该 <code>varPool(List&lt;Property&gt;)</code>合并为一个 varPool,在合并过程中,如果发现有相同的变量名的变量,按照以下逻辑处理</p>
@@ -60,7 +60,7 @@ Master 接收到 varPool 后,将其中为 OUT 的参数回写到 localParam 
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/backend/mechanism/overview.html b/zh-cn/development/backend/mechanism/overview.html
index c38ea5a..d3d72ca 100644
--- a/zh-cn/development/backend/mechanism/overview.html
+++ b/zh-cn/development/backend/mechanism/overview.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <!-- TODO 由于 side menu 不支持多个等级,所以新建了一个leading page存放 -->
 <ul>
 <li><a href="global-parameter.md">全局参数</a></li>
@@ -21,7 +21,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/backend/mechanism/task/switch.html b/zh-cn/development/backend/mechanism/task/switch.html
index 9e0921e..6296709 100644
--- a/zh-cn/development/backend/mechanism/task/switch.html
+++ b/zh-cn/development/backend/mechanism/task/switch.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <p>Switch任务类型的工作流程如下</p>
 <ul>
 <li>用户定义的表达式和分支流转的信息存在了taskdefinition中的taskParams中,当switch被执行到时,会被格式化为SwitchParameters。</li>
@@ -23,7 +23,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/backend/spi/alert.html b/zh-cn/development/backend/spi/alert.html
index 064a1bd..97a192f 100644
--- a/zh-cn/development/backend/spi/alert.html
+++ b/zh-cn/development/backend/spi/alert.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <h4>DolphinScheduler SPI 设计</h4>
 <p>DolphinScheduler 正在处于微内核 + 插件化的架构更改之中,所有核心能力如任务、资源存储、注册中心等都将被设计为扩展点,我们希望通过 SPI 来提高 DolphinScheduler 本身的灵活性以及友好性(扩展性)。</p>
 <p>告警相关代码可以参考 <code>dolphinscheduler-alert-api</code> 模块。该模块定义了告警插件扩展的接口以及一些基础代码,当我们需要实现相关功能的插件化的时候,建议先阅读此块的代码,当然,更建议你阅读文档,这会减少很多时间,不过文档有一定的后滞性,当文档缺失的时候,建议以源码为准(如果有兴趣,我们也欢迎你来提交相关文档),此外,我们几乎不会对扩展接口做变更(不包括新增),除非重大架构调整,出现不兼容升级版本,因此,现有文档一般都能够满足。</p>
@@ -70,7 +70,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/backend/spi/datasource.html b/zh-cn/development/backend/spi/datasource.html
index 1f93fe1..44ebcf3 100644
--- a/zh-cn/development/backend/spi/datasource.html
+++ b/zh-cn/development/backend/spi/datasource.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <h4>如何使用数据源?</h4>
 <p>数据源中心默认支持POSTGRESQL、HIVE/IMPALA、SPARK、CLICKHOUSE、SQLSERVER数据源。</p>
 <p>如果使用的是MySQL、ORACLE数据源则需要、把对应的驱动包放置lib目录下</p>
@@ -30,7 +30,7 @@ org.apache.dolphinscheduler.plugin.datasource.api.client.CommonDataSourceClient<
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/backend/spi/registry.html b/zh-cn/development/backend/spi/registry.html
index 31fc54d..755df70 100644
--- a/zh-cn/development/backend/spi/registry.html
+++ b/zh-cn/development/backend/spi/registry.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <h4>如何使用?</h4>
 <p>进行以下配置(以 zookeeper 为例)</p>
 <ul>
@@ -33,7 +33,7 @@ dolphinscheduler-service/src/main/resources/registry.properties<pre><code class=
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/backend/spi/task.html b/zh-cn/development/backend/spi/task.html
index d0ff902..6ee8e48 100644
--- a/zh-cn/development/backend/spi/task.html
+++ b/zh-cn/development/backend/spi/task.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <h4>如何进行任务插件开发?</h4>
 <p>org.apache.dolphinscheduler.spi.task.TaskChannel</p>
 <p>插件实现以上接口即可。主要包含创建任务(任务初始化,任务运行等方法)、任务取消,如果是 yarn 任务,则需要实现 org.apache.dolphinscheduler.plugin.task.api.AbstractYarnTask。</p>
@@ -23,7 +23,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/development-environment-setup.html b/zh-cn/development/development-environment-setup.html
index 490d428..a268930 100644
--- a/zh-cn/development/development-environment-setup.html
+++ b/zh-cn/development/development-environment-setup.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <h2>前置条件</h2>
 <p>在搭建 DolphinScheduler 开发环境之前请确保你已经安装一下软件</p>
 <ul>
@@ -145,7 +145,7 @@ npm run start
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/e2e-test.html b/zh-cn/development/e2e-test.html
new file mode 100644
index 0000000..2269809
--- /dev/null
+++ b/zh-cn/development/e2e-test.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+  <meta name="keywords" content="e2e-test">
+  <meta name="description" content="e2e-test">
+  <title>e2e-test</title>
+  <link rel="shortcut icon" href="/img/favicon.ico">
+  <link rel="stylesheet" href="/build/vendor.23870e5.css">
+</head>
+<body>
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+<h2>一、前置知识:</h2>
+<h3>1、E2E 测试与单元测试的区别</h3>
+<p>E2E,是“End to End”的缩写,可以翻译成“端到端”测试。它模仿用户,从某个入口开始,逐步执行操作,直到完成某项工作。与单元测试不同,后者通常需要测试参数、参数类型、参数值、参数数量、返回值、抛出错误等,目的在于保证特定函数能够在任何情况下都稳定可靠完成工作。单元测试假定只要所有函数都正常工作,那么整个产品就能正常工作。</p>
+<p>相对来说,E2E 测试并没有那么强调要覆盖全部使用场景,它关注的<strong>一个完整的操作链是否能够完成</strong>。对于 Web 前端来说,还关注<strong>界面布局、内容信息是否符合预期</strong>。</p>
+<p>比如,登陆界面的 E2E 测试,关注用户是否能够正常输入,正常登录;登陆失败的话,是否能够正确显示错误信息。至于输入不合法的内容是否处理,并不是所关注的重点。</p>
+<h3>2、Selenium 测试框架</h3>
+<p><a href="(https://www.selenium.dev/)">Selenium</a> 是一种开源测试工具,用于在 Web 浏览器上执行自动化测试。该框架使用 WebDriver 通过浏览器的原生组件,转化 Web Service 的命令为浏览器 native 的调用来完成操作。简单来说,就是模拟浏览器,对于页面的元素进行选择操作。</p>
+<p>WebDriver 是一个 API 和协议,它定义了一个语言中立的接口,用于控制 web 浏览器的行为。 每个浏览器都有一个特定的 WebDriver 实现,称为驱动程序。驱动程序是负责委派给浏览器的组件,并处理与 Selenium 和浏览器之间的通信。</p>
+<p>Selenium 框架通过一个面向用户的界面将所有这些部分连接在一起, 该界面允许透明地使用不同的浏览器后端, 从而实现跨浏览器和跨平台自动化。</p>
+<h2>二、E2E 测试</h2>
+<h3>1、E2E-Pages</h3>
+<p>DolphinScheduler 的 E2E 测试使用 docker-compose 部署,当前测试的为单机模式,主要用于检验一些例如“增删改查”基本功能,后期如需做集群验证,例如不同服务之间的协作,或者各个服务之间的通讯机制,可参考 <code>deploy/docker/docker-compose.yml</code>来配置。</p>
+<p>对于 E2E 测试(前端这一块),使用 <a href="https://www.selenium.dev/documentation/guidelines/page_object_models/">页面模型</a> 的形式,主要为每一个页面建立一个对应的模型。下面以登录页为例:</p>
+<pre><code class="language-java"><span class="hljs-keyword">package</span> org.apache.dolphinscheduler.e2e.pages;
+
+<span class="hljs-keyword">import</span> org.apache.dolphinscheduler.e2e.pages.common.NavBarPage;
+<span class="hljs-keyword">import</span> org.apache.dolphinscheduler.e2e.pages.security.TenantPage;
+
+<span class="hljs-keyword">import</span> org.openqa.selenium.WebElement;
+<span class="hljs-keyword">import</span> org.openqa.selenium.remote.RemoteWebDriver;
+<span class="hljs-keyword">import</span> org.openqa.selenium.support.FindBy;
+<span class="hljs-keyword">import</span> org.openqa.selenium.support.ui.ExpectedConditions;
+<span class="hljs-keyword">import</span> org.openqa.selenium.support.ui.WebDriverWait;
+
+<span class="hljs-keyword">import</span> lombok.Getter;
+<span class="hljs-keyword">import</span> lombok.SneakyThrows;
+
+<span class="hljs-meta">@Getter</span>
+<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginPage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NavBarPage</span> </span>{
+    <span class="hljs-meta">@FindBy(id = &quot;inputUsername&quot;)</span>
+    <span class="hljs-keyword">private</span> WebElement inputUsername;
+
+    <span class="hljs-meta">@FindBy(id = &quot;inputPassword&quot;)</span>
+    <span class="hljs-keyword">private</span> WebElement inputPassword;
+
+    <span class="hljs-meta">@FindBy(id = &quot;btnLogin&quot;)</span>
+    <span class="hljs-keyword">private</span> WebElement buttonLogin;
+
+    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">LoginPage</span><span class="hljs-params">(RemoteWebDriver driver)</span> </span>{
+        <span class="hljs-keyword">super</span>(driver);
+    }
+
+    <span class="hljs-meta">@SneakyThrows</span>
+    <span class="hljs-function"><span class="hljs-keyword">public</span> TenantPage <span class="hljs-title">login</span><span class="hljs-params">(String username, String password)</span> </span>{
+        inputUsername().sendKeys(username);
+        inputPassword().sendKeys(password);
+        buttonLogin().click();
+
+        <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">10</span>)
+            .until(ExpectedConditions.urlContains(<span class="hljs-string">&quot;/#/security&quot;</span>));
+
+        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> TenantPage(driver);
+    }
+}
+</code></pre>
+<p>在测试过程中,我们只针对所需要关注的元素进行测试,而非页面中的所有元素,所以在登陆页面只对用户名、密码和登录按钮这些元素进行声明。通过 Selenium 测试框架所提供的 FindBy 接口来查找 Vue 文件中对应的 id 或 class。</p>
+<p>此外,在测试过程中,并不会直接去操作元素,一般选择封装对应的方法,以达到复用的效果。例如想要登录的话,直接传入用户名和密码,通过 <code>public TenantPage login()</code> 方法去操作所传入的元素,从而达到实现登录的效果,即当用户完成登录之后,跳转到安全中心(默认进入到租户管理页面)。</p>
+<p>在安全中心页面(SecurityPage)提供了 goToTab 方法,用于测试对应侧栏的跳转,主要包括:租户管理(TenantPage)、用户管理(UserPage)、工作组管理(WorkerGroupPge)和队列管理(QueuePage)。这些页面的实现方式同理,主要测试表单的输入、增加和删除按钮是否能够返回出对应的页面。</p>
+<pre><code class="language-java"> <span class="hljs-keyword">public</span> &lt;T extends SecurityPage.Tab&gt; <span class="hljs-function">T <span class="hljs-title">goToTab</span><span class="hljs-params">(Class&lt;T&gt; tab)</span> </span>{
+        <span class="hljs-keyword">if</span> (tab == TenantPage.class) {
+            WebElement menuTenantManageElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                    .until(ExpectedConditions.elementToBeClickable(menuTenantManage));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, menuTenantManageElement);
+            <span class="hljs-keyword">return</span> tab.cast(<span class="hljs-keyword">new</span> TenantPage(driver));
+        }
+        <span class="hljs-keyword">if</span> (tab == UserPage.class) {
+            WebElement menUserManageElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                    .until(ExpectedConditions.elementToBeClickable(menUserManage));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, menUserManageElement);
+            <span class="hljs-keyword">return</span> tab.cast(<span class="hljs-keyword">new</span> UserPage(driver));
+        }
+        <span class="hljs-keyword">if</span> (tab == WorkerGroupPage.class) {
+            WebElement menWorkerGroupManageElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                    .until(ExpectedConditions.elementToBeClickable(menWorkerGroupManage));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, menWorkerGroupManageElement);
+            <span class="hljs-keyword">return</span> tab.cast(<span class="hljs-keyword">new</span> WorkerGroupPage(driver));
+        }
+        <span class="hljs-keyword">if</span> (tab == QueuePage.class) {
+            menuQueueManage().click();
+            <span class="hljs-keyword">return</span> tab.cast(<span class="hljs-keyword">new</span> QueuePage(driver));
+        }
+        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnsupportedOperationException(<span class="hljs-string">&quot;Unknown tab: &quot;</span> + tab.getName());
+    }
+</code></pre>
+<p><img src="../../img/e2e-test/SecurityPage.png" alt="SecurityPage"></p>
+<p>对于导航栏选项的跳转,在<code>org/apache/dolphinscheduler/e2e/pages/common/NavBarPage.java</code> 中提供了 goToNav 的方法。当前支持的页面为:项目管理(ProjectPage)、安全中心(SecurityPage)和资源中心(ResourcePage)。</p>
+<pre><code class="language-java">    <span class="hljs-keyword">public</span> &lt;T extends NavBarItem&gt; <span class="hljs-function">T <span class="hljs-title">goToNav</span><span class="hljs-params">(Class&lt;T&gt; nav)</span> </span>{
+        <span class="hljs-keyword">if</span> (nav == ProjectPage.class) {
+            WebElement projectTabElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                .until(ExpectedConditions.elementToBeClickable(projectTab));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, projectTabElement);
+            <span class="hljs-keyword">return</span> nav.cast(<span class="hljs-keyword">new</span> ProjectPage(driver));
+        }
+
+        <span class="hljs-keyword">if</span> (nav == SecurityPage.class) {
+            WebElement securityTabElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                .until(ExpectedConditions.elementToBeClickable(securityTab));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, securityTabElement);
+            <span class="hljs-keyword">return</span> nav.cast(<span class="hljs-keyword">new</span> SecurityPage(driver));
+        }
+
+        <span class="hljs-keyword">if</span> (nav == ResourcePage.class) {
+            WebElement resourceTabElement = <span class="hljs-keyword">new</span> WebDriverWait(driver, <span class="hljs-number">60</span>)
+                .until(ExpectedConditions.elementToBeClickable(resourceTab));
+            ((JavascriptExecutor)driver).executeScript(<span class="hljs-string">&quot;arguments[0].click();&quot;</span>, resourceTabElement);
+            <span class="hljs-keyword">return</span> nav.cast(<span class="hljs-keyword">new</span> ResourcePage(driver));
+        }
+
+        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnsupportedOperationException(<span class="hljs-string">&quot;Unknown nav bar&quot;</span>);
+    }
+</code></pre>
+<h3>2、E2E-Cases</h3>
+<p>当前所支持的 E2E 测试案例,主要包括:文件管理、项目管理、队列管理、租户管理、用户管理、Worker 分组管理和工作流测试。</p>
+<p><img src="../../img/e2e-test/E2E_Cases.png" alt="E2E_Cases"></p>
+<p>下面以租户管理测试为例,前文已经说明,我们使用 docker-compose 进行部署,所以每个测试案例,都需要以注解的形式引入对应的文件。</p>
+<p>使用 Selenium 所提供的 RemoteWebDriver 来加载浏览器。在每个测试案例开始之前都需要进行一些准备工作。比如:登录用户、跳转到对应的页面(根据具体的测试案例而定)。</p>
+<pre><code class="language-java">    <span class="hljs-meta">@BeforeAll</span>
+    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span> </span>{
+        <span class="hljs-keyword">new</span> LoginPage(browser)
+                .login(<span class="hljs-string">&quot;admin&quot;</span>, <span class="hljs-string">&quot;dolphinscheduler123&quot;</span>) <span class="hljs-comment">// 登录进入租户界面</span>
+                .goToNav(SecurityPage.class) <span class="hljs-comment">// 安全中心</span>
+                .goToTab(TenantPage.class)
+        ;
+    }
+</code></pre>
+<p>在完成准备工作之后,就是正式的测试案例编写。我们使用 @Order() 注解的形式,用于模块化,确认测试顺序。在进行测试之后,使用断言来判断测试是否成功,如果断言返回 true,则表示创建租户成功。可参考创建租户的测试代码:</p>
+<pre><code class="language-java">    <span class="hljs-meta">@Test</span>
+    <span class="hljs-meta">@Order(10)</span>
+    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">testCreateTenant</span><span class="hljs-params">()</span> </span>{
+        <span class="hljs-keyword">final</span> TenantPage page = <span class="hljs-keyword">new</span> TenantPage(browser);
+        page.create(tenant);
+
+        await().untilAsserted(() -&gt; assertThat(page.tenantList())
+                .as(<span class="hljs-string">&quot;Tenant list should contain newly-created tenant&quot;</span>)
+                .extracting(WebElement::getText)
+                .anyMatch(it -&gt; it.contains(tenant)));
+    }
+</code></pre>
+<p>其余的都是类似的情况,可参考具体的源码来理解。</p>
+<p><a href="https://github.com/apache/dolphinscheduler/tree/dev/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases">https://github.com/apache/dolphinscheduler/tree/dev/dolphinscheduler-e2e/dolphinscheduler-e2e-case/src/test/java/org/apache/dolphinscheduler/e2e/cases</a></p>
+<h2>三、补充</h2>
+<p>在本地运行 E2E 测试的时候,可以配置 <code>-Dlocal=true</code> 参数,用于连接本地,方便对于 UI 界面的更改。</p>
+<p><img src="../../img/e2e-test/Dlocal.png" alt="Dlocal"></p>
+<p>在本地运行过程中,如果出现连接超时,可增大加载时间,建议 30 及其以上。</p>
+<p><img src="../../img/e2e-test/timeout.png" alt="timeout"></p>
+<p>测试的运行过程将会以 MP4 的文件格式存在。</p>
+<p><img src="../../img/e2e-test/MP4.png" alt="MP4"></p>
+</div></section><footer class="footer-container"><div class="footer-body"><div><h3>联系我们</h3><h4>有问题需要反馈?请通过以下方式联系我们。</h4></div><div class="contact-container"><ul><li><a href="/zh-cn/community/development/subscribe.html"><img class="img-base" src="/img/emailgray.png"/><img class="img-change" src="/img/emailblue.png"/><p>邮件列表</p></a></li><li><a href="https://twitter.com/dolphinschedule"><img class="img-base" src="/img/twittergray.png"/><img class="img-change" src="/img/twitterblue.png"/><p [...]
+  <script src="//cdn.jsdelivr.net/npm/react@15.6.2/dist/react-with-addons.min.js"></script>
+  <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
+  <script>window.rootPath = '';</script>
+  <script src="/build/vendor.e29fe5d.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
+  <script>
+    var _hmt = _hmt || [];
+    (function() {
+      var hm = document.createElement("script");
+      hm.src = "https://hm.baidu.com/hm.js?4e7b4b400dd31fa015018a435c64d06f";
+      var s = document.getElementsByTagName("script")[0];
+      s.parentNode.insertBefore(hm, s);
+    })();
+  </script>
+  <!-- Global site tag (gtag.js) - Google Analytics -->
+  <script async src="https://www.googletagmanager.com/gtag/js?id=G-899J8PYKJZ"></script>
+  <script>
+    window.dataLayer = window.dataLayer || [];
+    function gtag(){dataLayer.push(arguments);}
+    gtag('js', new Date());
+
+    gtag('config', 'G-899J8PYKJZ');
+  </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/zh-cn/development/e2e-test.json b/zh-cn/development/e2e-test.json
new file mode 100644
index 0000000..360d2af
--- /dev/null
+++ b/zh-cn/development/e2e-test.json
@@ -0,0 +1,6 @@
+{
+  "filename": "e2e-test.md",
+  "__html": "<h1>DolphinScheduler — E2E 自动化测试</h1>\n<h2>一、前置知识:</h2>\n<h3>1、E2E 测试与单元测试的区别</h3>\n<p>E2E,是“End to End”的缩写,可以翻译成“端到端”测试。它模仿用户,从某个入口开始,逐步执行操作,直到完成某项工作。与单元测试不同,后者通常需要测试参数、参数类型、参数值、参数数量、返回值、抛出错误等,目的在于保证特定函数能够在任何情况下都稳定可靠完成工作。单元测试假定只要所有函数都正常工作,那么整个产品就能正常工作。</p>\n<p>相对来说,E2E 测试并没有那么强调要覆盖全部使用场景,它关注的<strong>一个完整的操作链是否能够完成</strong>。对于 Web 前端来说,还关注<strong>界面布局、内容信息是否符合预期</strong>。</p>\n<p>比如,登陆界面的 E2E 测试,关注用户是否能够正常输入,正常登录;登陆失败的�
 �,是否能够正确显示错误信息。至于输入不合法的内容是否处理,并不是所关注的重点。</p>\n<h3>2、Selen [...]
+  "link": "/dist/zh-cn/development/e2e-test.html",
+  "meta": {}
+}
\ No newline at end of file
diff --git a/zh-cn/development/frontend-development.html b/zh-cn/development/frontend-development.html
index 17ebddb..2b20039 100644
--- a/zh-cn/development/frontend-development.html
+++ b/zh-cn/development/frontend-development.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <h3>技术选型</h3>
 <pre><code>Vue mvvm 框架
 
@@ -515,7 +515,7 @@ test.then(res =&gt; {
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {
diff --git a/zh-cn/development/have-questions.html b/zh-cn/development/have-questions.html
index c5367d5..53f6fd8 100644
--- a/zh-cn/development/have-questions.html
+++ b/zh-cn/development/have-questions.html
@@ -10,7 +10,7 @@
   <link rel="stylesheet" href="/build/vendor.23870e5.css">
 </head>
 <body>
-  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
+  <div id="root"><div class="md2html development-page" data-reactroot=""><header class="header-container header-container-dark"><div class="header-body"><span class="mobile-menu-btn mobile-menu-btn-dark"></span><a href="/zh-cn/index.html"><img class="logo" src="/img/hlogo_white.svg"/></a><div class="search search-dark"><span class="icon-search"></span></div><span class="language-switch language-switch-dark">En</span><div class="header-menu"><div><ul class="ant-menu whiteClass ant-menu-li [...]
 <h2>StackOverflow</h2>
 <p>如果在使用上有疑问,建议你使用StackOverflow标签 <a href="https://stackoverflow.com/questions/tagged/apache-dolphinscheduler">apache-dolphinscheduler</a>,这是一个DolphinScheduler用户问答的活跃论坛。</p>
 <p>使用StackOverflow时的快速提示:</p>
@@ -75,7 +75,7 @@
   <script src="//cdn.jsdelivr.net/npm/react-dom@15.6.2/dist/react-dom.min.js"></script>
   <script>window.rootPath = '';</script>
   <script src="/build/vendor.e29fe5d.js"></script>
-  <script src="/build/development.md.2eb2fd9.js"></script>
+  <script src="/build/development.md.627e13d.js"></script>
   <script>
     var _hmt = _hmt || [];
     (function() {