Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

44 changed files with 0 additions and 2880 deletions

23
.gitignore vendored
View File

@ -1,23 +0,0 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 515 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

BIN
1tab.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 515 KiB

View File

@ -1 +0,0 @@
<!doctype html><html lang="zh-hans-CN" class="notranslate translated-ltr" translate="no"><head><title>GitLink | 新一代开源创新服务平台</title><meta charset="utf-8"><meta name="Keywords" content="GitLink, git, 开源, 代码托管, 项目管理, 版本控制, 代码分享, 项目协作, 协同开发平台"><meta name="description" content="GitLink 是一个新一代的开源创新服务平台,提供分布式协作开发、流水线运维、代码分析等功能,基于 Git 打造分布式代码托管环境。"><meta property="og:title" content="GitLink | 确实开源"/><meta property="og:type" content="website"/><meta property="og:url" content="https://gitlink.org.cn/"/><meta property="og:image" content="https://www.gitlink.org.cn/images/logo.png"/><meta property="og:image:alt" content="GitLink | 确实开源"/><meta property="og:site_name" content="GitLink"/><meta property="og:description" content="GitLink 是一个新一代的开源创新服务平台,提供分布式协作开发、流水线运维、代码分析等功能,基于 Git 打造分布式代码托管环境。"/><meta name="hostname" content="gitlink.org.cn"><meta name="keyboard-shortcuts-preference" content="all"><meta name="expected-hostname" content="gitlink.org.cn"><meta name="go-import" content="gitlink.org.cn git https://gitlink.org.cn"><meta name="octolytics-dimension-user_login" content="GitLink"><meta name="octolytics-dimension-repository_nwo" content="GitLink"><meta name="octolytics-dimension-repository_network_root_nwo" content="GitLink"><meta name="theme-color" content="#000000"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="referrer" content="always"><meta name="google-site-verification" content="rGWc47_e6dmJlLtT6ngl3WSiXMsY8FCcll2dbdlNHm0"/><meta name="viewport" content=""><link rel="canonical" href="https://gitlink.org.cn" data-turbo-transient=""><link rel="fluid-icon" href="https://www.gitlink.org.cn/images/logo.png" title="GitLink"><link rel="manifest" href="/build//manifest.json"><link rel="stylesheet" href="/build/css/alex/alex.all.global.min.css"><link rel="stylesheet" href="/build/css/iconfont.css"><link rel="stylesheet" href="/build/css/editormd.min.css"><link rel="stylesheet" href="/build/css/gitlink.min.css"><link href="/build/static/css/main.ca90844f.chunk.css" rel="stylesheet"></head><body><div id="md_div" style="display:none"></div><div id="root" class="page -layout-v -fit widthunit"></div><div id="picture_display" style="display:none"></div><script src="https://gw.alipayobjects.com/os/lib/react/16.14.0/umd/react.production.min.js"></script><script src="https://gw.alipayobjects.com/os/lib/react-dom/16.14.0/umd/react-dom.production.min.js"></script><script src="/build/js/jquery-1.8.3.min.js"></script><script src="/build/js/js_min_all.js"></script><script src="/build/js/codemirror/codemirror.js"></script><script src="/build/js/editormd/editormd.min.js"></script><script src="/build/js/codemirror/merge/merge.js"></script><script src="/build/js/alex/moment.js"></script><script src="https://gw.alipayobjects.com/os/lib/alipay/alex/2.0.19/bundle/alex.all.global.min.js"></script><script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script><script src="/build/./static/js/runtime~main.6c69de13.js"></script><script src="/build/./static/js/main.0a826963.chunk.js"></script><script>var _hmt=_hmt||[];!function(){var t=document.createElement("script");t.src="https://hm.baidu.com/hm.js?7e2def1fe918f15f9f1c5c061f69b256";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e)}(),window.onload=function(){$(".newContainer").delegate("a.anchors","click",(function(){let t=$(this).offset().top-180;return $("html,body").animate({scrollTop:t},10),window.location.hash=$(this).attr("name"),!1}))}</script></body></html>

View File

@ -1,102 +0,0 @@
# Errors
Errors are indicated by returning an `error` as an additional return value from a function. A `nil` value means that there was no error.
` error `s can be turned into strings by calling `Error`, their only method. You can create an error from a string by calling `errors.New`:
```go
if failure {
return errors.New("inverse tachyon pulse failed")
}
```
or by using `fmt.Errorf`:
```go
if failure {
return fmt.Errorf("inverse tachyon pulse failed")
}
```
Error strings should not start with a capital letter because they'll often be prefixed before printing:
```go
err := TryInverseTachyonPulse()
if err != nil {
fmt.Printf("failed to solve problem: %s\n", err)
}
```
If you expect calling code to be able to handle an error, you can distinguish classes of errors either by returning special values, or new types. You only need to distinguish differences that the calling code could be expected to handle in this way as the string allows one to communicate the details of the error.
`io.EOF` is a special value that signals the end of a stream. You can compare error values directly against io.EOF.
If you want to carry extra data with the error, you can use a new type:
```go
type ParseError struct {
Line, Col int
}
func (p ParseError) Error() string {
return fmt.Sprintf("parse error on line %d, column %d", p.Line, p.Col)
}
```
If you want to create a constant string error, you can use a named type string:
```go
type errorConst string
const ErrTooManyErrors errorConst = "too many errors found."
func (e errorConst) Error() string {
return string(e)
}
```
Calling code would test for a special type of `error` by using a type switch:
```go
switch err := err.(type) {
case ParseError:
PrintParseError(err)
}
```
## Naming
Error types end in `"Error"` and error variables start with `"Err"` or `"err"`:
```go
package somepkg
// ParseError is type of error returned when there's a parsing problem.
type ParseError struct {
Line, Col int
}
var ErrBadAction = errors.New("somepkg: a bad action was performed")
// -----
package foo
func foo() {
res, err := somepkgAction()
if err != nil {
if err == somepkg.ErrBadAction {
}
if pe, ok := err.(*somepkg.ParseError); ok {
line, col := pe.Line, pe.Col
// ....
}
}
}
```
## References
* Errors (specification): https://go.dev/ref/spec#Errors
* Package `errors`: https://pkg.go.dev/errors/
* Type switches: https://go.dev/ref/spec#TypeSwitchStmt

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,2 @@
# tesgsdfsgfd # tesgsdfsgfd
1111
222

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,32 +0,0 @@
{"task_id": "0", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "1", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "2", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "3", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "4", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "5", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "6", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "7", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "8", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "9", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "10", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "11", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "12", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "13", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "14", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "15", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "16", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "17", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "18", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "19", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "20", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "21", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "22", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "23", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "24", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "25", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "26", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "27", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "28", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "29", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "30", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "31", "raw_outputs": ["码:C"], "question_type": "choice"}

View File

@ -1,16 +0,0 @@
{"task_id": "0", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "1", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "2", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "3", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "4", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "5", "raw_outputs": ["A"], "question_type": "choice"}
{"task_id": "6", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "7", "raw_outputs": [" A"], "question_type": "choice"}
{"task_id": "8", "raw_outputs": ["答 \nD答D"], "question_type": "choice"}
{"task_id": "9", "raw_outputs": [" D答案\nD"], "question_type": "choice"}
{"task_id": "10", "raw_outputs": ["(A)"], "question_type": "choice"}
{"task_id": "11", "raw_outputs": ["仓库正确答案是C。\n\n解释国务院是中国的最高行政机关是负责执行国家法律、法规和政策领导国家行政工作的最高权力机关。"], "question_type": "choice"}
{"task_id": "12", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "13", "raw_outputs": ["explanation: \n我国exexplanation: \n我国宪法规定中华人民共和国的一切权力属于人民。人民是指以工人、农民、知识分子为主体的社会劳动人民。这是根据中国共产党的性质和宗旨提出的中国共产党是中国工人阶级的先锋同时是中国人民和中华民族的先锋队因此答案为选项C. 人民。"], "question_type": "choice"}
{"task_id": "14", "raw_outputs": ["库中没有相关内容"], "question_type": "choice"}
{"task_id": "15", "raw_outputs": [" A"], "question_type": "choice"}

View File

@ -1,9 +0,0 @@
{"task_id": "0", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "1", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "2", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "3", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "4", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "5", "raw_outputs": ["A"], "question_type": "choice"}
{"task_id": "6", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "7", "raw_outputs": ["A"], "question_type": "choice"}
{"task_id": "8", "raw_outputs": [" B"], "question_type": "choice"}

View File

@ -1,50 +0,0 @@
{"task_id": "0", "raw_outputs": ["annC"], "question_type": "choice"}
{"task_id": "1", "raw_outputs": [" B《六》是一部古代兵法名著作者是姜。《六韬》又称《太公兵法》或《太公兵法六韬》是由周朝著名军事家姜子所著是古代兵法的重要典籍之一。\n解释\n《六韬》的作者为周朝著名军事姜子牙也被称为太公或太公兵法。它是一部古代兵法名著主要内容包括《文韬》、《武》、《龙韬》、《豹韬》、《猴韬》、《鹰韬》。《六韬》集古代兵法之大成成为中国兵法史上的重要经典。"], "question_type": "choice"}
{"task_id": "2", "raw_outputs": [" B(正确答案)"], "question_type": "choice"}
{"task_id": "3", "raw_outputs": ["码:C"], "question_type": "choice"}
{"task_id": "4", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "5", "raw_outputs": ["A"], "question_type": "choice"}
{"task_id": "6", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "7", "raw_outputs": [" A"], "question_type": "choice"}
{"task_id": "8", "raw_outputs": ["答 \nD答D"], "question_type": "choice"}
{"task_id": "9", "raw_outputs": [" D答案\nD"], "question_type": "choice"}
{"task_id": "10", "raw_outputs": ["(A)"], "question_type": "choice"}
{"task_id": "11", "raw_outputs": ["仓库正确答案是C。\n\n解释国务院是中国的最高行政机关是负责执行国家法律、法规和政策领导国家行政工作的最高权力机关。"], "question_type": "choice"}
{"task_id": "12", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "13", "raw_outputs": ["explanation: \n我国exexplanation: \n我国宪法规定中华人民共和国的一切权力属于人民。人民是指以工人、农民、知识分子为主体的社会劳动人民。这是根据中国共产党的性质和宗旨提出的中国共产党是中国工人阶级的先锋同时是中国人民和中华民族的先锋队因此答案为选项C. 人民。"], "question_type": "choice"}
{"task_id": "14", "raw_outputs": ["库中没有相关内容"], "question_type": "choice"}
{"task_id": "15", "raw_outputs": [" A"], "question_type": "choice"}
{"task_id": "16", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "17", "raw_outputs": [" C"], "question_type": "choice"}
{"task_id": "18", "raw_outputs": [" D"], "question_type": "choice"}
{"task_id": "19", "raw_outputs": [" A"], "question_type": "choice"}
{"task_id": "20", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "21", "raw_outputs": [" C"], "question_type": "choice"}
{"task_id": "22", "raw_outputs": [" D"], "question_type": "choice"}
{"task_id": "23", "raw_outputs": [" A"], "question_type": "choice"}
{"task_id": "24", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "25", "raw_outputs": [" C"], "question_type": "choice"}
{"task_id": "26", "raw_outputs": [" D"], "question_type": "choice"}
{"task_id": "27","raw_outputs": ["仓库正确答案是C。\n\n解释国务院是中国的最高行政机关是负责执行国家法律、法规和政策领导国家行政工作的最高权力机关。"], "question_type": "choice"}
{"task_id": "28", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "29", "raw_outputs": [" C"], "question_type": "choice"}
{"task_id": "30", "raw_outputs": [" D"], "question_type": "choice"}
{"task_id": "31", "raw_outputs": ["仓库正确答案是C。\n\n解释国务院是中国的最高行政机关是负责执行国家法律、法规和政策领导国家行政工作的最高权力机关。"], "question_type": "choice"}
{"task_id": "32", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "33", "raw_outputs": [" C"], "question_type": "choice"}
{"task_id": "34", "raw_outputs": [" D"], "question_type": "choice"}
{"task_id": "35", "raw_outputs": ["仓库正确答案是C。\n\n解释国务院是中国的最高行政机关是负责执行国家法律、法规和政策领导国家行政工作的最高权力机关。"], "question_type": "choice"}
{"task_id": "36", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "37", "raw_outputs": [" C"], "question_type": "choice"}
{"task_id": "38", "raw_outputs": ["库中没有相关内容"], "question_type": "choice"}
{"task_id": "39", "raw_outputs": [" A"], "question_type": "choice"}
{"task_id": "40", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "41", "raw_outputs": ["库中没有相关内容"], "question_type": "choice"}
{"task_id": "42", "raw_outputs": [" D"], "question_type": "choice"}
{"task_id": "43", "raw_outputs": [" A"], "question_type": "choice"}
{"task_id": "44", "raw_outputs": [" B"], "question_type": "choice"}
{"task_id": "45", "raw_outputs": ["库中没有相关内容"], "question_type": "choice"}
{"task_id": "46", "raw_outputs": [" D"], "question_type": "choice"}
{"task_id": "47", "raw_outputs": [" A"], "question_type": "choice"}
{"task_id": "48", "raw_outputs": ["库中没有相关内容"], "question_type": "choice"}
{"task_id": "49", "raw_outputs": [" C"], "question_type": "choice"}

File diff suppressed because one or more lines are too long

View File

@ -1,116 +0,0 @@
"""
# coding=utf-8
@Time:2024/7/3 11:16
@Auth:jiafeng
@File:conftest.py
"""
import os
import shutil
import time
import pytest
import allure
from playwright.sync_api import sync_playwright
from CBB.pages.login_page import LoginPage
from CBB.setting import login_base_dir, RunConfig
from CBB.utils.read_file import load_yaml
# 导入pytest的fixture装饰器以及request对象用于定义fixture函数和访问测试上下文
@pytest.fixture(scope="function")
def init_browser(request, browser_type=RunConfig.browser[0]):
"""
初始化浏览器驱动并打开基础URL根据指定的浏览器类型默认从配置中读取
支持的浏览器类型有Chromium, Firefox, WebKit
参数:
- request: pytest请求对象用于注册清理函数
- browser_type: 字符串默认为从RunConfig获取的第一个浏览器类型
函数功能细节:
1. 初始化Playwright实例以与浏览器交互
2. 根据browser_type参数选择并启动相应的浏览器实例禁用无头模式并最大化窗口
3. 配置新浏览器上下文以录制视频设定视频保存目录及尺寸
4. 在新上下文中创建页面供测试使用
5. 定义清理函数fin用于测试结束时执行资源清理及视频录制文件处理
6. 使用yield关键字在执行测试前返回页面和上下文对象测试后自动调用fin进行清理工作
"""
# 初始化Playwright
playwright = sync_playwright().start()
# 根据浏览器类型启动对应浏览器
if browser_type == 'chromium':
browser = playwright.chromium.launch(headless=False, args=['--start-maximized'])
elif browser_type == 'firefox':
browser = playwright.firefox.launch(headless=False, args=['--start-maximized'])
elif browser_type == 'webkit':
browser = playwright.webkit.launch(headless=False, args=['--start-maximized'])
else:
# 如果提供的浏览器类型不受支持,则抛出错误
raise ValueError("不支持的浏览器类型。支持的浏览器: chromium, firefox, webkit.")
# 配置浏览器上下文以录制视频
context = browser.new_context(no_viewport=True,
record_video_dir="videos/",
record_video_size={"width": 1280, "height": 720})
# 在新上下文中创建页面
page = context.new_page()
def fin():
# 清理操作尝试获取视频路径关闭浏览器上下文和浏览器停止Playwright
try:
video_path = page.video.path()
except Exception as e:
video_path = None
context.close()
browser.close()
playwright.stop()
# 将录制的视频附加到Allure测试报告中
if video_path:
allure.attach.file(video_path, name="test_video", attachment_type=allure.attachment_type.MP4)
# 注册清理函数确保测试结束后执行fin
request.addfinalizer(fin)
# 返回页面和上下文给测试函数使用
yield page, context
@allure.title("登录成功测试用例")
@allure.step("操作步骤: 登录")
@pytest.fixture(scope="function")
def test_login_success(init_browser):
"""
进行登录操作并验证登录成功
"""
page, context = init_browser
login_page = LoginPage(page)
# 从配置文件中读取登录URL
login_url = load_yaml(path=login_base_dir, key='baseUrl')
with allure.step(f"打开登录页面:{login_url}"):
page.goto(login_url)
# 从配置文件中读取用户名和密码
# username = load_yaml(path='config.yaml', key='username')
# password = load_yaml(path='config.yaml', key='password')
# with allure.step("输入用户名"):
login_page.enter_username('wjf')
# with allure.step("输入密码"):
login_page.enter_password('6')
# with allure.step("点击登录按钮"):
login_page.click_login_button()
page.wait_for_timeout(1000) # 等待1秒钟以确保页面加载完成
# 确认登录成功
with allure.step("验证登录成功"):
assert login_page.is_logged_in()
yield page, context

View File

@ -1 +0,0 @@
fsafsafsafsaf

Binary file not shown.

View File

@ -1,108 +0,0 @@
.glcc-container {
background-image: linear-gradient(
180deg,
#ebf2ff 0%,
#ebf2ff 43.09%,
#f3f4f8 100%
);
padding-bottom: 120px;
.glcc_breadcrumb {
padding: 18px 0;
border-bottom: 1px dashed #bec5d5;
margin-bottom: 30px;
}
.head_introduce {
background: #e4edff;
padding: 20px;
}
.head_tit {
color: #000000;
font-size: 15px;
line-height: 2;
}
.head_content {
color: #6c7283;
font-size: 14px;
line-height: 38px;
}
.head_bold {
font-weight: 700;
color: #333;
}
}
.glcc-main {
width: 1200px;
margin: 0 auto;
}
.-task-sidebar .glccHelp {
height: auto;
width: 38px;
padding: 6px 10px;
text-align: center;
background-color: #f6f9fe;
border: 1px solid #ffffff;
border-radius: 2px;
box-shadow: 0px 0px 8px rgba(55, 148, 255, 0.16);
color: #1e1e1e;
font-size: 14px;
line-height: 20px;
word-break: break-word;
cursor: pointer;
.icon-bangzhuzhongxinicon,
.icon-bangzhuzhongxinicon1{
color: #0654d6;
margin-left: -3px;
}
.icon-zanting {
color: #0654d6;
}
&:hover {
color: #ffffff;
background-color: #466aff;
.icon-bangzhuzhongxinicon,
.icon-bangzhuzhongxinicon1,
.icon-zanting {
color: #ffffff;
}
}
.glccList{
width: 21px;
position: relative;
left: -2px;
}
}
.qqChatBox {
position: fixed;
.ant-popover-arrow {
display: none;
}
}
.qqChat {
margin: -12px -16px;
background-image: linear-gradient(180deg, #f8faff 0%, #dee7ff 100%);
border: 1px solid #ffffff;
border-radius: 4px;
box-shadow: 0px 0px 6px rgba(121, 154, 245, 0.27);
padding: 25px 40px;
text-align: center;
.qqMa {
padding: 8px;
margin-bottom: 15px;
text-align: center;
background-image: radial-gradient(
ellipse 50% 50% at 50% 50%,
rgba(255, 255, 255, 0) 0%,
rgba(239, 243, 251, 0) 100%
);
box-shadow: 0px 0px 6px #aecaff inset;
img {
width: 120px;
}
}
.qqTip {
color: #5769a5;
font-size: 14px;
line-height: 24px;
}
}

434
index.tsx
View File

@ -1,434 +0,0 @@
import { Input , Badge , Avatar , Menu } from 'antd';
import { Dispatch, Link, connect } from 'umi';
import './index.less';
import { EnterpriseModelState } from '@/models/enterprise';
import { UsersModelState } from '@/models/user';
import { useEffect, useState } from 'react';
import { WorkStandModelState } from '@/models/workStand';
import { Table , Row , Col , Progress , Pagination , Spin } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { workItemIcon , workItemType , workItemStatus} from '@/constant/project';
import { StatusTag } from '@/components/Tags/Tags';
import { toTimeFormat } from '@/utils/util';
// import { iterationStatusList } from '@/constant/project';
import styles from './index.less';
import NoData from '@/components/NoData';
interface HomePageProps {
enterprise: EnterpriseModelState;
user:UsersModelState
dispatch:Dispatch,
workStand:WorkStandModelState
}
const Index: React.FC<HomePageProps> = ({ enterprise ,user , dispatch , workStand }) => {
const { currentUser } = user;
const { identifier:enterIdentifier } = enterprise;
const [ search , setSearch ] = useState<string>("");
const [ selectKey , setSelectKey ] = useState<string>("assignedme");
const [ statictisData , setStatictisData ] = useState<any>([]);
const [ dataSource , setDataSource ] = useState<any>([]);
const [ workLoading , setWorkLoading ] =useState<boolean>(true);
const [ workPage , setWorkPage ] = useState<number>(1);
const [ workTotal , setWorkTotal ] = useState<number>(0);
const [ projectData , setProjectData ] = useState<any>([]);
const [ projectLoading , setProjectLoading ] =useState<boolean>(true);
const [ projectPage , setProjectPage ] = useState<number>(1);
const [ projectTotal , setProjectTotal ] = useState<number>(0);
const [ planData , setPlanData ] = useState<any>([]);
const [ planLoading , setPlanLoading ] =useState<boolean>(true);
const [ planPage , setPlanPage ] = useState<number>(1);
const [ planTotal , setPlanTotal ] = useState<number>(0);
const [ authoredmeCount , setAuthoredmeCount ] = useState<number>(0);
const [ assignedmeCount , setAssignedmeCount ] = useState<number>(0);
function getCurrentTime() {
const currentHour = new Date().getHours();
if (currentHour >= 6 && currentHour < 9) {
return "早上好!";
} else if (currentHour >= 9 && currentHour < 12) {
return "上午好!";
}else if (currentHour >= 12 && currentHour < 14) {
return "中午好!";
} else if (currentHour >= 14 && currentHour < 18) {
return "下午好!";
} else if(currentHour >= 18) {
return "晚上好!";
}
}
useEffect(()=>{
if(enterIdentifier){
getStatistics();
}
},[enterIdentifier])
useEffect(()=>{
if(enterIdentifier){
getIteratioins();
}
},[enterIdentifier,planPage])
useEffect(()=>{
if(enterIdentifier){
getProjects();
}
},[enterIdentifier,projectPage])
useEffect(()=>{
if(enterIdentifier){
setWorkPage(1);
getWorkItem(1);
}
},[enterIdentifier,selectKey,search])
// 获取我的工作台统计信息
async function getStatistics() {
let res:any = await dispatch({
type:"workStand/getMyStatistics",
})
setStatictisData(res?.data);
setAssignedmeCount(res?.data?.assignedmeCount);
setAuthoredmeCount(res?.data?.authoredmeCount);
}
// 获取我的迭代
async function getIteratioins() {
setPlanLoading(true);
let res:any = await dispatch({
type:"workStand/getMyIterations",
payload:{
pageNum:planPage,pageSize:5,statusIds:1
}
})
if(res?.code === 200){
setPlanData(res?.rows);
setPlanTotal(res?.total);
}
setPlanLoading(false);
}
// 获取我的项目
async function getProjects() {
setProjectLoading(true);
let res:any = await dispatch({
type:"workStand/getMyProjects",
payload:{
pageNum:projectPage,pageSize:4,status:1
}
})
if(res?.code === 200){
setProjectData(res?.rows);
setProjectTotal(res?.total);
}
setProjectLoading(false);
}
// 获取我的工作项
async function getWorkItem(page:number) {
setWorkLoading(true);
let res:any = await dispatch({
type:"workStand/getMyWorkItem",
payload:{
participantCategory:selectKey,page,limit:5,category:"opened",keyword:search
}
})
if(res?.code === 200){
setDataSource(res?.data?.issues);
setWorkTotal(res?.data?.total_count);
if(selectKey === "assignedme"){
setAssignedmeCount(res?.data?.opened_count);
}else{
setAuthoredmeCount(res?.data?.opened_count);
}
}
setWorkLoading(false);
}
const columns: ColumnsType<API.projects.workItem>=[
{
title: '标题',
dataIndex: 'subject',
key: 'subject',
width: '40%',
ellipsis:{
showTitle: false
},
render:(value:string,record:any)=>{
return(
<a className="alignCenter" onClick={async()=>{
await dispatch({
type:"project/setCurrent",
payload: { id: record?.pm_project_id }
})
await dispatch({
type:'project/setOpen',
payload:{
open:false,
id:record?.id,
editOpen:true,
pmIssueType:record?.pm_issue_type,
parent:"workStand",
onOk:getWorkItem
}
})
window.history.pushState({},"0",`/${enterIdentifier}/projects/${record?.pm_project_id}/${workItemType[record?.pm_issue_type]}/${record?.id}`)
}}><i className={`iconfontColor ${workItemIcon[record?.pm_issue_type]} font16 mr10`} /><span className={"hide"}>{value}</span></a>
)
}
},{
title: '状态',
dataIndex: 'status',
key: 'status',
width: '14%',
ellipsis:{
showTitle: false
},
render:(value:any,record:any)=>{
let type = record?.pm_issue_type === 1? workItemType.demand : record?.pm_issue_type === 2 ? workItemType.task :workItemType.bug;
let connectIssueStatus = workItemStatus[type];
let text = value;
text.name = connectIssueStatus[value?.id];
return <StatusTag item={ text }></StatusTag>
}
},{
title: '优先级',
dataIndex: 'priority',
key: 'priority',
width: '15%',
ellipsis:{
showTitle: false
},
render:(value:any)=>{
return <div className={"alignCenter"}>
<i style={{display: "inlineBlock", width: 7, height: 7, borderRadius:" 50%",marginRight: 6, background:`${value?.pm_color}`}}></i>
{ value?.name }
</div>
}
},{
title: '负责人',
dataIndex: 'assigners',
key: 'assigners',
width: '18%',
ellipsis:{
showTitle: false
},
render:(value:any)=>{
let list = value.length > 0 ? value.map((i:any)=>{return i?.name}):[];
// <Avatar shape={"circle"} style={{backgroundColor:"#C1DAFF",marginRight:6}} size={24} src={value?.image_url} alt="" />
return list?.length ? list.toString() :"--"
}
},{
title: '时间',
dataIndex: 'created_at',
key: 'created_at',
ellipsis:{
showTitle: false
},
align:"center",
render:(value:any)=>{
return <span>{toTimeFormat(value)}</span>
}
}
]
const planColumns:ColumnsType<API.projects.iteration>=[
{
title: '标题',
dataIndex: 'sprintName',
key: 'sprintName',
ellipsis:{
showTitle: false
},
render:(value:string,record:any)=>{
return(
<Link to={`/${enterIdentifier}/projects/${record?.pmsProjectId}/iteration/${record?.id}`} className={"font15 fontw400 col0d0Text alignCenter"}><img src={require("@/assets/image/workStand/planTitle.png")} alt="" className="mr20"/><span className="hide">{value}</span></Link>
)
}
},
// {
// title: '状态',
// dataIndex: 'status',
// key: 'status',
// width: '15%',
// ellipsis:{
// showTitle: false
// },
// render:(value:any,record:any)=>{
// const item = iterationStatusList.find(e => e.id === +value)
// return item ? <StatusTag item={ item }></StatusTag> : ''
// }
// },
{
title: '负责人',
dataIndex: 'sprintAssignee',
key: 'sprintAssignee',
width: '13%',
ellipsis:{
showTitle: false
},
render:(value:any)=>{
return <span><Avatar shape={"circle"}gap={0} style={{backgroundColor:"#fff",marginRight:6}} size={24} src={value?.avatar} alt="" />{value?.nickName}</span>
}
},{
title: '工作进度',
dataIndex: 'sprintIssuesStatistics',
key: 'sprintIssuesStatistics',
width: '25%',
ellipsis:{
showTitle: false
},
render:(value:any,record:any)=>{
let closeCount = +value?.count_closed;
let totalCount = +value?.count_total;
return <span className="alignCenter"><Progress percent={+(closeCount/totalCount).toFixed(2)*100} style={{marginLeft:10,marginBottom:5}} strokeColor={"#2C75FF"} showInfo={false}/>{closeCount}/{totalCount}</span>
}
},{
title: '工作进度',
dataIndex: 'sprintIssuesStatistics',
key: 'sprintIssuesStatistics',
width: '25%',
ellipsis:{
showTitle: false
},
render:(value:any,record:any)=>{
let closeCount = +value?.hour_closed;
let totalCount = +value?.hour_total;
return <span className="alignCenter"><Progress percent={+(closeCount/totalCount).toFixed(2)*100} style={{marginLeft:10,marginBottom:5}} strokeColor={"#00AA82"} showInfo={false}/>{!(closeCount && totalCount) ? 0 :+(+(closeCount||0) / +(totalCount)).toFixed(2)*100}%</span>
}
}
]
return (
<div className={styles.staging}>
<div className={`${styles.stagingInfo} ${styles.stagingItem}`}>
<div className={`alignCenter ${styles.staginInfoFirst}`}>
{/* <Badge dot={true} offset={[-6,6]} color={"#14CA54"}> </Badge>*/}
<Avatar shape={"circle"} style={{backgroundColor:"#C1DAFF"}} size={48} src={currentUser?.avatar} />
<span className={`ml15 fontw500 col283Text font20`}>{currentUser?.nickName}</span>
<span className={`ml20 fontw400 col283Text font16`}>{getCurrentTime()}</span>
</div>
<ul className={styles.stagingCard}>
<li>
<img src={require(`@/assets/image/workStand/task.png`)} alt="" />
<div>
<span>{statictisData?.projectTaskCount}</span>
<span></span>
</div>
</li>
<li>
<img src={require(`@/assets/image/workStand/needs.png`)} alt="" />
<div>
<span>{statictisData?.projectRequirementCount}</span>
<span></span>
</div>
</li>
<li>
<img src={require(`@/assets/image/workStand/issue.png`)} alt="" />
<div>
<span>{statictisData?.projectBugCount}</span>
<span></span>
</div>
</li>
{
statictisData?.productRequirementCount ?
<li>
<img src={require(`@/assets/image/workStand/productNeeds.png`)} alt="" />
<div>
<span>{statictisData?.productRequirementCount}</span>
<span></span>
</div>
</li>
:""
}
</ul>
</div>
<div className={`${styles.stagingWorkItem} ${styles.stagingItem}`}>
<div className={`alignCenter ${styles.titles}`}>
<img src={require('@/assets/image/workStand/workitem.png')} width="22px" style={{marginTop:"3px"}} alt="" />
<span className="ml5"></span>
<Input
className="search-input ml30"
value={ search }
onBlur={ (e:any) => { setSearch(e.target.value) } }
onChange={ (e:any) => { setSearch(e.target.value) } }
suffix={ <i className="iconfont">&#xe6d1;</i> }
placeholder="搜索..."
/>
<img onClick={()=>{getWorkItem(workPage)}} style={{marginLeft:"auto",cursor:"pointer"}} src={require('@/assets/image/workStand/reset.png')} alt=""/>
</div>
<Menu mode="horizontal" selectedKeys={[selectKey]} onSelect={(e:any)=>{setSelectKey(e.key)}} className={styles.menusStyle}>
<Menu.Item key="assignedme"><Badge count={assignedmeCount} showZero style={{backgroundColor:"rgba(136, 149, 168, 0.07)",color:"#445A7A",marginLeft:4}}/></Menu.Item>
<Menu.Item key="authoredme"><Badge count={authoredmeCount} showZero style={{backgroundColor:"rgba(136, 149, 168, 0.07)",color:"#445A7A",marginLeft:4}}/></Menu.Item>
</Menu>
<Table
columns={columns}
dataSource={dataSource}
showHeader={false}
rowClassName={styles.rowStyle}
loading={workLoading}
pagination={{current:workPage,total:workTotal,pageSize:5,showQuickJumper:false,showSizeChanger:false,onChange:(p:number)=>{setWorkPage(p);getWorkItem(p)},hideOnSinglePage:true }}
/>
</div>
<Row justify={"start"}>
<Col span={8}>
<div className={`${styles.stagingProjects} ${styles.stagingItem}`}>
<div className={`alignCenter ${styles.titles}`}>
<img src={require('@/assets/image/project/reportChart.png')} width="28px" style={{marginTop:"7px"}} alt="" />
<span className="ml3"></span>
<img onClick={()=>{getProjects()}} style={{marginLeft:"auto",cursor:"pointer"}} src={require('@/assets/image/workStand/reset.png')} alt=""/>
</div>
<Spin spinning={projectLoading}>
{
projectData?.length > 0 ?
<div className={styles.listItems}>
{
projectData.map((i:any,key:number)=>{
return(
<div className={styles.listItemCard} key={key}>
<div className="alignCenter mb10">
<Link to={`/${enterIdentifier}/projects/${i?.id}`} className={`col283Text font16 fontw500 hide`} style={{flex:'1'}}>{i?.projectName}</Link>
<span className={styles.cardTagicon}><i className="iconfont icon-xiangmuicon font18"/></span>
</div>
<p className="mb15"><span className="mr40"> {i?.projectIssuesCount}</span><span> {i?.projectMemberCount}</span></p>
<Avatar shape={"circle"} style={{backgroundColor:"#F3F8FF",marginRight:6}} size={20} src={i?.projectAssignee?.avatar} alt="" /><span>{i?.projectAssignee?.nickName}</span>
</div>
)
})
}
</div>
: <NoData />
}
<div style={{textAlign:"right",paddingBottom:15,paddingTop:12}}>
<Pagination current={projectPage} pageSize={4} hideOnSinglePage={true} total={projectTotal} onChange={(p:number)=>{setProjectPage(p)}}/>
</div>
</Spin>
</div>
</Col>
<Col span={16}>
<div className={`${styles.stagingPlan} ${styles.stagingItem} ml25`}>
<div className={`alignCenter ${styles.titles}`} style={{marginBottom:0}}>
<img src={require('@/assets/image/workStand/plan.png')} width="22px" style={{marginTop:"3px"}} alt="" />
<span className="ml5"></span>
<img onClick={()=>{getIteratioins()}} style={{marginLeft:"auto",cursor:"pointer"}} src={require('@/assets/image/workStand/reset.png')} alt=""/>
</div>
<Table
columns={planColumns}
dataSource={planData}
showHeader={false}
rowClassName={styles.rowStyle}
loading={planLoading}
pagination={{current:planPage,total:planTotal,pageSize:5,showQuickJumper:false,showSizeChanger:false,onChange:(p:number)=>{setPlanPage(p)},hideOnSinglePage:true }}
/>
</div>
</Col>
</Row>
</div>
);
};
export default connect(({ enterprise , user , workStand }: { enterprise: EnterpriseModelState , user:UsersModelState , workStand:WorkStandModelState }) => ({enterprise,user,workStand}))(Index);

View File

@ -1,14 +0,0 @@
@projects @issue
Feature: 开源项目模块
: Issue IssueIssue
Background:
Given 访GitLink<host>
And cookies
And 访<project_url>
Scenario: 登录状态下在测试仓库新建Issue
Given
| | | |
| ${generate_name()} | ${generate_identifier()} | ${generate_name()} |
When []tab

Binary file not shown.

View File

@ -1 +0,0 @@
ok

16
test.sh
View File

@ -1,16 +0,0 @@
#!/bin/bash
week=`date +%u`
if [ $week=1 ]
then echo "今天是星期一"
elif [ $week=2 ]
then echo "今天是星期二"
elif [ $week=3 ]
then echo "今天是星期三"
elif [ $week=4 ]
then echo "今天是星期四"
elif [ $week=5 ]
then echo "今天星期五"
elif [ $week=6 ]
then echo "今天是星期六"
else echo "今天是星期日"
fi

View File

@ -1 +0,0 @@
111

View File

@ -1,200 +0,0 @@
# -*- coding: utf-8 -*-
# @Time : 2023/10/31 14:39
# @Author : floraachy
# @File : test_repo_issue_flow.py
# @Software: PyCharm
# @Desc:
# 标准库导入
import os
import re
# 第三方库导入
import allure
import pytest
from playwright.sync_api import BrowserContext
from loguru import logger
# 本地应用/模块导入
from config.path_config import FILES_DIR
from page_objects.projects.issue.repo_issue_page import RepoIssuePage
from page_objects.projects.issue.repo_new_issue_page import RepoNewIssuePage
from page_objects.projects.issue.repo_issue_detail_page import RepoIssueDetailPage
from page_objects.projects.issue.repo_edit_issue_page import RepoEditIssuePage
from utils.requests_utils.api_workflow import get_api_data, api_work_flow
from config.path_config import INTERFACE_DIR
from config.global_vars import GLOBAL_VARS
@pytest.mark.issue
class TestRepoIssueFlow:
"""疑修"""
cases = {
"test_new_search_edit_delete_issue": [
{"issue_title": "new - ${generate_paragraph(nb=1)}",
"issue_desc": "${generate_paragraph()}",
"issue_file": " gitlinklogo2.png, gitlinklogo3.jpg",
"new_issue_success_message": "疑修创建成功!",
"edit_issue_title": "update - ${generate_paragraph(nb=1)}",
"edit_issue_desc": "${generate_paragraph()}",
"delete_issue_file": "gitlinklogo3.jpg",
"file_delete_success_message": "附件删除成功",
"update_issue_success_message": "疑修更新成功!",
"delete_issue_confirm_message": "您确定要删除当前疑修?",
"delete_issue_success_message": "疑修删除成功!",
"run": True}],
"test_search_copy_delete_issue": [
{"new_issue_file": "导入TOC订单.xls, login_demo.yaml",
"copy_issue_title": "update - ${generate_paragraph(nb=1)}",
"copy_issue_desc": "${generate_paragraph()}",
"copy_issue_file": " gitlinklogo2.png, gitlinklogo3.jpg",
"copy_issue_success_message": " 疑修复制成功!",
"delete_issue_confirm_message": "您确定要删除当前疑修?",
"delete_issue_success_message": "疑修删除成功!",
"run": True}]
}
@pytest.fixture(autouse=True)
def start_for_each(self, request, default_user_context: BrowserContext):
logger.info("for each--start: 测试用户打开新建疑修页面")
# 测试用户
user_page = default_user_context.new_page()
self.create_issue_page = RepoNewIssuePage(user_page)
yield
logger.info("for each--end: 后置操作")
@pytest.mark.parametrize("case")
def test_new_issue_success(self, case):
"""
登录 --> 新建疑修 --> 删除疑修
"""
# 进入疑修创建页面
self.create_issue_page.navigate(repo_owner=GLOBAL_VARS.get("repo_owner"),
repo_identifier=GLOBAL_VARS.get("repo_identifier"))
issue_title = case.get("issue_title")
issue_desc = case.get("issue_desc")
# 兼容一下中文逗号,发现有中文逗号,替换为英文逗号, 同时去除file前后空格与保存文件的目录拼接出文件的绝对路径
issue_files = [os.path.join(FILES_DIR, f.strip()) for f in
case.get("issue_file").replace("", ",").split(",")]
# 创建疑修
self.create_issue_page.new_issue_flow(issue_title=issue_title, issue_desc=issue_desc, issue_file=issue_files,
success_message=case.get("new_issue_success_message"))
#
# issue_page = RepoIssuePage(self.create_issue_page.page)
#
# # 点击【疑修(Issue)】导航栏
# issue_page.click_issue_nav()
# # 页面进入:${repo_owner}/${repo_identifier}/issues
# issue_page.have_url(
# f"{GLOBAL_VARS.get('repo_owner')}/{GLOBAL_VARS.get('repo_identifier')}/issues")
# # 在搜索框中输入疑修标题,点击搜索图标
# issue_page.search_issue_by_keyword(text=issue_title)
# # 点击疑修标题
# issue_page.click_issue_title_on_list(title=issue_title)
# # 断言 - 页面进入疑修详情页, 检查网页标题,疑修标题,内容及附件
# expected_issue_title = issue_title
# # 断言 - 网页标题模糊匹配expected['issue_title']-疑修
# issue_page.have_title(re.compile(f"{expected_issue_title}-疑修-.*"))
# # 断言 - 疑修标题,内容及附件
# expected_issue_file = issue_files if isinstance(issue_files, list) else [issue_files]
# expect_files = []
# for issue_file in expected_issue_file:
# expect_files.append(os.path.basename(issue_file) if os.path.isabs(issue_file) else issue_file)
# RepoIssueDetailPage(issue_page.page).assert_issue_title_desc_attachment(expect_tittle=issue_title,
# expect_desc=issue_desc,
# expect_attachment=expect_files)
#
# edit_issue_title = case.get("edit_issue_title")
# edit_issue_desc = case.get("edit_issue_desc")
# # 检查一下需要删除的附件是否传递错误
# # 兼容一下中文逗号,发现有中文逗号,替换为英文逗号, 同时去除file前后空格与保存文件的目录拼接出文件的绝对路径
# delete_issue_files = [os.path.join(FILES_DIR, f.strip()) for f in
# case.get("delete_issue_file").replace("", ",").split(",")]
# logger.error(f"编辑疑修时,需要删除的疑修附件不是疑修有的附件:{delete_issue_files}")
#
# # 编辑疑修
# edit_issue_page = RepoEditIssuePage(issue_page.page)
# edit_issue_page.edit_issue_flow(issue_title=edit_issue_title, issue_desc=edit_issue_desc,
# delete_issue_file=delete_issue_files,
# success_message=case.get("update_issue_success_message"))
# # 断言 - 页面进入疑修详情页, 检查网页标题,疑修标题,内容及附件
# # 断言网页标题模糊匹配expected['issue_title']-疑修
# edit_issue_page.have_title(re.compile(f"{edit_issue_title}-疑修-.*"))
# # 断言 - 疑修标题,内容及附件
# expected_issue_file = list(set(issue_files) - set(delete_issue_files))
# expect_files = []
# for issue_file in expected_issue_file:
# expect_files.append(os.path.basename(issue_file) if os.path.isabs(issue_file) else issue_file)
#
# edit_issue_page.assert_issue_title_desc_attachment(expect_tittle=edit_issue_title,
# expect_desc=edit_issue_desc,
# expect_attachment=expect_files)
# 删除疑修
RepoIssuePage(page).delete_issue(confirm_message=case.get("delete_issue_confirm_message"),
success_message=case.get("delete_issue_success_message"))
@pytest.mark.parametrize("case")
def test_search_copy_delete_issue(self, page: Page, case):
"""
前提条件当前存在一个疑修
1. 登录
2. 访问仓库的疑修详情页
3. 复制疑修
4. 删除刚刚复制的疑修
"""
# 我有一个疑修,疑修带有附件,附件名称是
# 通过接口登录获取登录cookies
if not GLOBAL_VARS.get("cookies"):
login_api = get_api_data(api_file_path=os.path.join(INTERFACE_DIR, "test_gitlink_login.yaml"),
key="gitlink_login_01")
res = api_work_flow(req_data=login_api, source=GLOBAL_VARS)
login_cookies = res["cookies"]
GLOBAL_VARS["cookies"] = login_cookies
# 上传附件获取附件id
issue_files = [f.strip() for f in case.get("new_issue_file").replace("", ",").split(",")]
GLOBAL_VARS["attachment_ids"] = []
for file in issue_files:
GLOBAL_VARS["file_name"] = file
upload_file_api = get_api_data(
api_file_path=os.path.join(INTERFACE_DIR, "projects", "test_gitlink_upload_files.yaml"),
key="gitlink_upload_file_01")
res = api_work_flow(req_data=upload_file_api, source=GLOBAL_VARS)
GLOBAL_VARS["attachment_ids"].append(res["attachment_id"])
# 新建疑修
new_issue_api = get_api_data(
api_file_path=os.path.join(INTERFACE_DIR, "projects", "issues", "test_gitlink_repo_new_issue.yaml"),
key="gitlink_repo_new_issue_01")
res = api_work_flow(req_data=new_issue_api, source=GLOBAL_VARS)
# 访问疑修详情页
issue_index = res["issue_index"]
CommonPage(page).navigate(
f"{GLOBAL_VARS.get('repo_owner')}/{GLOBAL_VARS.get('repo_identifier')}/issues/{issue_index}")
issue_title = case.get("copy_issue_title")
issue_desc = case.get("copy_issue_desc")
# 兼容一下中文逗号,发现有中文逗号,替换为英文逗号, 同时去除file前后空格与保存文件的目录拼接出文件的绝对路径
issue_files = [os.path.join(FILES_DIR, f.strip()) for f in
case.get("copy_issue_file").replace("", ",").split(",")]
# 复制疑修
RepoIssuePage(page).copy_issue(issue_title=issue_title, issue_desc=issue_desc, issue_file=issue_files,
success_message=case.get("copy_issue_success_message"))
# 断言 - 页面进入疑修详情页, 检查网页标题,疑修标题,内容及附件
# 断言网页标题模糊匹配expected['issue_title']-疑修
CommonPage(page).assert_page_title(re.compile(f"{issue_title}-疑修-.*"))
# 断言 - 疑修标题,内容及附件
expected_issue_file = issue_files if isinstance(issue_files, list) else [issue_files]
expect_files = []
for issue_file in expected_issue_file:
expect_files.append(os.path.basename(issue_file) if os.path.isabs(issue_file) else issue_file)
RepoIssuePage(page).assert_issue_title_desc_attachment(expect_tittle=issue_title, expect_desc=issue_desc,
expect_attachment=expect_files)
RepoIssuePage(page).assert_issue_attachments(expect_files)
# 删除疑修
RepoIssuePage(page).delete_issue(confirm_message=case.get("delete_issue_confirm_message"),
success_message=case.get("delete_issue_success_message"))

View File

@ -1,95 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.2">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="测试计划" enabled="true">
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.tearDown_on_shutdown">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="线程组" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true">
<stringProp name="LoopController.loops">1</stringProp>
<boolProp name="LoopController.continue_forever">false</boolProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">1</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
<boolProp name="ThreadGroup.delayedStart">false</boolProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP请求" enabled="true">
<boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">https://www.gitlink.org.cn/Gitlink/forgeplus/issues/3676</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.BROWSER_COMPATIBLE_MULTIPART">false</boolProp>
<boolProp name="HTTPSampler.image_parser">false</boolProp>
<boolProp name="HTTPSampler.concurrentDwn">false</boolProp>
<stringProp name="HTTPSampler.concurrentPool">6</stringProp>
<boolProp name="HTTPSampler.md5">false</boolProp>
<intProp name="HTTPSampler.ipSourceType">0</intProp>
</HTTPSamplerProxy>
<hashTree/>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="响应断言" enabled="true">
<collectionProp name="Asserion.test_strings"/>
<stringProp name="Assertion.custom_message"></stringProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">16</intProp>
</ResponseAssertion>
<hashTree/>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="查看结果树" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>true</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<sentBytes>true</sentBytes>
<url>true</url>
<threadCounts>true</threadCounts>
<idleTime>true</idleTime>
<connectTime>true</connectTime>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>

View File

@ -1,5 +0,0 @@
摄氏度东风
sdfdsfds
sdfds发

Binary file not shown.

Binary file not shown.

Binary file not shown.