fasttest-selenium 0.1.6
WEB自动化快速编写工具
Requires Python: >=3.6
Keywords: selenium,WEB自动化,关键字驱动

# 框架介绍
fasttest-selenium 是由Python语言开发的WEB端自动化框架，通过yaml编写相应的action即可调用Selenium API完成自动化测试。  
[文档介绍](https://www.yuque.com/books/share/99dcee33-a99d-4364-ab48-eb511d7ceb2d?#)
## idea
- 能否同时运行多个不同的浏览器，解决兼容性测试问题
- 通过插件快速输入关键字
## 已完成功能
- selenium 90%的Action支持
- 可拓展的公共方法和公共函数
- 高度还原steps的报告输出
## 待完成功能
- 数据类型优化：支持自定义复杂数据结构
- 结果报告优化：支持图片放大


# 快速体验
## 框架下载

fasttest-selenium已经发布到Python PyPi平台，可通过以下两种方式完成安装
1.在终端输入下方命令进行安装：

```bash
pip3 install fasttest-selenium
```

2.可前往[代码仓库](https://github.com/Jodeee/fasttest_selenium)直接clone或下载源码。

> 下载源码后需要将包导入到当前项目中

## 项目依赖

该框架在Python3.7版本下开发，部分功能依赖第三方模块，故需要安装以下模块

1. `PyYAML` 用于解析yaml测试用例文件

```basic
pip3 install PyYAML
```

2. `selenium` WEB自动化框架

```basic
pip3 install selenium
```

3. `colorama` 日志高亮输出

```basic
pip3 install colorama
```

4.`opencv-contrib-python` 图片对比识别

```basic
pip3 install opencv-contrib-python==3.4.2.16
```

> 说明：opencv在3.4.2以上版本使用其算法需要**授权确认**，该版本最高支持Python3.7，如不需要图片对比能力，可安装最新版Python和opencv-contrib-python

## 测试Demo

[Demo](https://github.com/Jodeee/fasttestSeleniumDemo)包含完整项目结构以及关键字测试用例，下载后可通过运行 `runtest.py` 启动测试执行

# 项目结构

## 项目树状图

```
├── Common           // 自定义关键字库  
|   ├── common.yaml  // 自定义关键字文件
├── Resource         // 文件资源目录
|   ├── test.png     // 图片资源
├── Report           // 结果报告目录  
├── Scripts          // 脚本函数目录 
|   ├── __init__.py  // 包标识文件
|   ├── test.py      // 脚本文件
├── TestCase         // 测试用例目录
|   ├── test.yaml    // 测试用例文件
├── config.yaml      // 项目配置文件  
├── data.json        // 数据配置文件  
├── runtest.py       // 项目执行文件
```

## config 项目配置

`config.yaml` 包含了项目运行时必要参数，结构如下：  
`driver` 固定参数，值为 `selenium`   
`browser` 指定浏览器，包括 `chrome` 、 `firefox` 、 `safari` 、 `ie` 、 `opera`   
`isReset` 每条用例执行完后是否重置浏览器，推荐设置为 `True` 
`saveScreenshot` 执行步骤是否保存截图，如果为`True` 将大大增加执行时间，推荐设置为 `False` ，只在执行异常时保存截图  
`implicitlyWait` 隐式等待时间  
`maxWindow` 窗口最大化  
`desiredcaps` 启动参数配置，会根据 `browser` 拿到对应浏览器参数  
`driver` 浏览器驱动，如驱动未添加环境变量中，可通过此参数指定驱动路径  
`options` 浏览器启动参数，会自动添加到对应浏览器的`options`  
`testcast` 用例执行路径，可指定某一条用例路径或者某一文件夹下面所有用例  


```yaml
driver: selenium
browser: chrome
isReset: True
saveScreenshot: False
implicitlyWait: 10
maxWindow: True
desiredcaps:
    - chrome:
        - driver: '/Users/xiongjunjie/Desktop/chromedriver'
          options: # 无头模式运行
            - '--headless'
            - '--dissble-gpu'
            - '--window-size=1920,1050'
      firefox:
        - driver: '/Users/xiongjunjie/Desktop/geckodriver'
          options:
            - '--headless'
            - '--dissble-gpu'
            - '--window-size=1920,1050'

testcase:
    - TestCase/common/
    - TestCase/selenium/cookies.yaml

```

## data 数据配置

`data.json` 为数据配置，结构如下：  
`variable` 全局变量配置，用例中可直接获取该配置下的数据  
`resource` 资源路径配置，用例中可直接访问该相对路径下的文件资源  
`keywords` 脚本函数配置，用例中可直接调用该配置下的函数  

```json
{
  "variable": {
    "userid": "admin",
    "password": 13456
  },
  "resource": {
    "baidu_logo": "Resource/baidu.png"
  },
  "keywords": [
    "keyDown",
    "getText"
  ]
}
```

例：直接调用 `keywords` 函数并传递userid的值和baidu_logo的路径

```yaml
- keyDown(${userid},${baidu_logo})
```

## runtest 执行入口

`runtest.py` 为整个项目执行入口，可直接执行该文件或在终端运行 `python3 runtest.py` 启动项目  
`start` 方法有返回整体执行结果，方便接入持续集成或者生成自定义报告           

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from fasttest_selenium import *

if __name__ == '__main__':

    project = Project()

    project.start()

```

## Common 自定义关键字

`Common` 目录用于存放自定义的关键字，类似于PO模式中的Page，可以将用例中公共逻辑抽离出来保存到这里，它需要一个关键字来表达它的作用，所以我们需要为它指定一个唯一的名字，以便于我们在用例中可调用。  
**关键字结构：**  
`common_action` 关键字名称，性感且唯一  
`description` 关键字描述，简短有力  
`input`  传入参数，一个不漏  
`output` 返回参数，暂未实现  
`steps` 执行步骤  
关键字定义：

```yaml
common_action:        
 description: 公共方法
 input: [key,value]
 output: []
 steps:
    - click(${value})
    - sleep(5)
    
common_action1:        
 description: 公共方法1
 input: [key,value]
 output: []
 steps:
    - click(${value})
    - sleep(5)
```

调用方式：在用例中call + 关键字名称为调用该关键字的语法，参数个数应和 `input` 相对应

```yaml
- call common_action('key','测试数据')
```

## Scripts 脚本函数

`Scripts` 为Python脚本目录，在 [`data.json`]下 `keywords` 中注册方法名后，就可直接在用例中调用脚本
如现有关键字无法完成的特殊操作，可以导入框架中 `driver` 模块，通过 `driver` 调用底层API  
函数定义：

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from fasttest_selenium.driver import *

def getText():
    '''
    调用selenium api获取当前页面标题
    '''
    log_info(driver.title)
    return driver.title

def getTest(test):
    '''
    普通函数
    '''
    log_info(test)
```

调用方式：如果需要拿到函数返回的数据，可以直接用变量保存，如不需要，可以直接调用函数

```yaml
- ${title} = getText() # 获取返回值
- getTest('测试数据') # 普通函数
```

## Resource 文件资源

`Resource` 目录下的文件资源在 [`data.json`](#nNDdu) 下 `resource` 中指定文件名称和相对路径后，可以直接在用例中访问该资源文件

```yaml
- matchImage(${baesImage}, ${baidu_logo})
```

## TestCase 测试用例

`TestCase` 用于存放测试用例，测试用例为 `YAML` 文件，如果对`YAML` 语法不熟悉可参考[菜鸟教程](https://www.runoob.com/w3cnote/yaml-intro.html)，用例结构如下：  
`module` 用例所属业务模块，同一业务下用例的`module` 应保持一致，在结果报告中它们将展示在同一个分组下面  
`skip` 是否跳过该用例，默认为false  
`description` 用例描述  
`steps` 用例步骤  

```yaml
module: selenium
skip: false
description: action相关
steps:
  - openUrl('https://www.baidu.com')
  # 检查元素
  - check('id=su')
  # 单击元素
  - click('id=su')
  # 右击元素
  - contextClick('id=su')
  # 双击元素
  - doubleClick('class=hot-refresh-text')
  # 按住鼠标左键
  - holdClick('class=hot-refresh-text')
```

## Report 结果报告

`Report` 为测试结果目录，用例执行完毕后会自动生成高度还原测试用例步骤的测试报告，可点击具体步骤
查看截图和错误信息

# 关键字

测试用例中的关键字包含4中场景，项目结构中已经介绍了自定义关键字 [`Common`](https://www.yuque.com/jodeee/vt6gkg/iqc0hn#yiqZY) 和 [`Scripts`](https://www.yuque.com/jodeee/vt6gkg/iqc0hn#YU0b2) ，接下来两种是固定关键字

## 讲在前面

在介绍关键字之前，先介绍下用例中经常用到的两个点

1. 关于变量的定义，占位符${} + 变量名test来表示这是一个变量，获取该变量同样如此
   1. 关于赋值：它可以直接被赋值或者其他关键字返回值给变量
   1. 关于取值：一条用例中${test}会从多个地方尝试获取值，所以具有一定优先级
      1. 最高优先级：如果在for循环中，会优先获取for循环迭代值
      1. 第二优先级：如果for循环中无法获取该变量，会尝试从当前用例中获取变量值
      1. 第三优先级：如果当前用例中未定义该变量，会判断是否在 `Common` 库中 `input` 有定义
      1. 第四优先级：如果以上三种均未获取该变量，会尝试从 `data.json` 下 `variable` 、 `resource` 获取变量值
2. 元素定位方法：selenium有八种元素定位方式，为了简化步骤描述，用例中按照 `type=element` 的方式即可定位到相关元素
   1. 元素定位方式：_id、name、class、tag_name、link_text、partial_link_text、xpath、css_selector_
   1. 例：点击百度按钮 click("id=su") 

![image.png](https://cdn.nlark.com/yuque/0/2020/png/499819/1608438016248-05bad871-ec48-4fb6-a6f1-c8bfc1c5ba62.png#align=left&display=inline&height=685&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1370&originWidth=2822&size=634969&status=done&style=none&width=1411)

## Selenium Action

### Browser

#### 打开网页(openUrl)

`openUrl` 打开一个网页，参数: `URL` 

```yaml
- ${url} = 'https://www.baidu.com'
- openUrl(${url})
# 或者
- openUrl('https://www.baidu.com')
```

对应Selenium API ：

```python
driver = webdriver.Chrome()
driver.get(url)
```

#### 关闭标签页或窗口(close)

`close` 关闭当前标签页或窗口

```yaml
- openUrl('https://www.baidu.com')
- close()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.close()
```

#### 后退(back)

`back` 退回到上一页

```yaml
- back()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.find_element_by_xpath('//*[@id="s-top-left"]/a[1]').click()
driver.back()
```

#### 前进(forward)

`forward` 前进到下一页

```yaml
- forward()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.find_element_by_xpath('//*[@id="s-top-left"]/a[1]').click()
driver.back()
driver.forward()
```

#### 刷新(refresh)

`refresh` 刷新当前页面

```yaml
- refresh()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.refresh()
```

#### 窗口最大化(maxWindow)

`maxWindow` 窗口最大化

```yaml
- maxWindow()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.maximize_window()
```

#### 窗口最小化(minWindow)

`minWindow` 窗口最小化

```yaml
- minWindow()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.minimize_window()
```

#### 窗口全屏(fullscreenWindow)

`fullscreenWindow` 窗口全屏

```yaml
- fullscreenWindow()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.fullscreen_window()
```

#### 设置窗口大小(setWindowSize)

`setWindowSize` 设置窗口大小，参数： `width` ， `height` 

```yaml
- setWindowSize(3000,2000)
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.set_window_size(3000,2000)
```

#### 设置窗口坐标(setWindowPosition)

`setWindowPosition` 设置窗口起始坐标，参数： `x` ， `y` 

```yaml
- setWindowPosition(10,20)
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.set_window_position(10,20)
```

#### 获取窗口大小($.getWindowSize)

`$.getWindowSize` 获取窗口大小

```yaml
- ${w_size} = $.getWindowSize()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
w_size = driver.get_window_size()
```

#### 获取窗口坐标($.getWindowPosition)

`$.getWindowPosition` 获取窗口起始坐标

```yaml
- ${w_position} = $.getWindowPosition()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
w_position = driver.get_window_position()
```

#### 获取当前窗口句柄($.getCurrentWindowHandle)

`$.getCurrentWindowHandle` 获取当前窗口句柄

```yaml
- ${handle} = $.getCurrentWindowHandle()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
handle = driver.current_window_handle
```

#### 获取所有窗口句柄($.getWindowHandles)

`$.getWindowHandles` 获取所有窗口句柄

```yaml
- ${handles} = $.getWindowHandles()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
handles = driver.window_handles
```

#### 切换窗口句柄(switchToWindow)

`switchToWindow` 切换窗口句柄，参数: `handle` 

> 获取所有的窗口句柄是无序的，建议用for循环切换窗口句柄

```yaml
- ${all_handle} = $.getWindowHandles()
- for ${handle} in ${all_handle}:
    # 切换窗口句柄
    - switchToWindow(${handle})
    - ${title} = $.getTitle()
    - if ${title} == '百度新闻——海量中文资讯平台':
        - break
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
handles = driver.window_handles
for handle in handles:
    # 切换窗口句柄
    switch_to.window(handle)
    title = driver.title
    if title == '百度新闻——海量中文资讯平台':
        break
```

#### 获取窗口标题($.getTitle)

`$.getTitle` 获取窗口标题

```yaml
- ${title} = $.getTitle()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
title = driver.title
```

#### 获取窗口URL($.getCurrentUrl)

`$.getCurrentUrl` 获取窗口URL

```yaml
- ${title} = $.getCurrentUrl()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
title = driver.current_url
```

#### 获取浏览器名称($.getName)

`$.getName` 获取浏览器名称

```yaml
- ${name} = $.getName()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
title = driver.name
```


### Action

#### 单击(click)

`click` 鼠标左键单击，参数: `element` 

```yaml
- click('id=su')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_id('su')
element.click()
```

#### 右击(contextClick)

`contextClick` 鼠标右键单击，参数: `element`

```yaml
- contextClick('id=su')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_id('su')
ActionChains(driver).context_click(element).perform()
```

#### 双击(doubleClick)

`doubleClick` 鼠标左键双击，参数: `element`

```yaml
- doubleClick('id=su')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_id('su')
ActionChains(driver).double_click(element).perform()
```

#### 长按(holdClick)

`holdClick` 长按鼠标左键不放，参数: `element`

```yaml
- holdClick('id=su')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_id('su')
ActionChains(driver).click_and_hold(element).perform()
```

#### 拖放元素到另一个元素位置(dragDrop)

`dragDrop` 拖放元素到另一个元素位置，参数: `element`，`target`

```yaml
- dragDrop('xpath=//*[@id="sbox"]/tbody/tr/td[1]/div[1]/a/img','id=s_btn_wr')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_xpath('//*[@id="sbox"]/tbody/tr/td[1]/div[1]/a/img')
target = find_element_by_id('s_btn_wr')
ActionChains(driver).drag_and_drop(element, target).perform()
```

#### 拖放元素到某个位置(dragDropByOffset)

`dragDropByOffset` _拖放元素到某个位置_，参数: `element` ， `x` ， `y` 

```yaml
- dragDropByOffset('xpath=//*[@id="sbox"]/tbody/tr/td[1]/div[1]/a/img',10,10)
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_xpath('//*[@id="sbox"]/tbody/tr/td[1]/div[1]/a/img')
ActionChains(driver).drag_and_drop_by_offset(element, 10, 10).perform()
```

#### 鼠标移动到某个位置(moveByOffset)

`moveByOffset` _鼠标从当前位置移动到某个坐标_，参数：`x` ， `y`

```yaml
- moveByOffset(10,10)
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
ActionChains(driver).move_by_offset(10, 10).perform()
```

#### 鼠标移动到某个元素(moveToElement)

`moveToElement` _鼠标移动到某个元素上_，参数: `element`

```yaml
- moveToElement('xpath=//*[@id="hotsearch-content-wrapper"]/li[1]/a/span[2]')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_xpath('//*[@id="hotsearch-content-wrapper"]/li[1]/a/span[2]')
ActionChains(driver).move_to_element(element).perform()
```

#### 鼠标_移动到距某个元素多少距离的位置_(moveToElementWithOffset)

`moveToElementWithOffset` 鼠标_移动到距某个元素(左上角坐标)多少距离的位置_，参数: `element` ， `x` ， `y`

```yaml
- moveToElementWithOffset('id=su',10,20)
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_id('su')
ActionChains(driver).move_to_element_with_offset(element, 10, 20).perform()
```

#### 输入(sendKeys)

`sendKeys` 输入文案，参数： `element` ， `Keys(可选)` ， `text` 

```yaml
- sendKeys('name=wd','测试文案') # 普通输入
# 复制粘贴
- sendKeys('name=wd','Keys.CONTROL', 'c') # control + c
- sendKeys('name=wd','Keys.CONTROL', 'v') # control + v
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_name('wd')
element.send_keys('测试文案')
# 复制粘贴
element.send_keys(Keys.CONTROL, 'c')
element.send_keys(Keys.CONTROL, 'v')
```

#### 清除(clear)

`clear` 清除输入框文案、元素选中状态

```yaml
- clear('name=wd')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_name('wd')
element.clear()
```

#### 执行JS(executeScript)

`executeScript` 执行JS代码，参数: `script`   

```yaml
- ${js} = "window.open('http://www.taobao.com')"
- executeScript(${js})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
js = "window.open('http://www.taobao.com')"
driver.execute_script(js)
```

#### 截图($.saveScreenshot)

`$.saveScreenshot` 对屏幕或者元素截图，参数: `element(可选，如果为空则截全屏)`， `name`   

```yaml
# 对元素截图，返回图片路径
- ${path} = $.saveScreenshot('id=su', 'biadu.png')
# 全屏截图，返回图片路径
- ${path} = $.saveScreenshot('biadu.png')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element = find_element_by_id('su')
# 元素截图
element.screenshot(path)
# 全屏截图
driver.save_screenshot(path)
```

### Element

#### 获取单个元素($.getElement)

`$.getElement` 获取单个元素，参数: `element`   

```yaml
# 获取单个元素 id|name|class|tag_name|link_text|partial_link_text|xpath|css_selector
- ${element_id} = $.getElement('id=su')
- ${element_name} = $.getElement('name=f')
- ${element_class} = $.getElement('class=s_ipt')
- ${element_tag_name} = $.getElement('tag_name=form')
- ${element_link_text} = $.getElement('link_text=新闻')
- ${element_partial_link_text} = $.getElement('partial_link_text=新')
- ${element_xpath} = $.getElement('xpath=//*[@id="su"]')
- ${element_css_selector} = $.getElement('css_selector=[name="wd"]')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
'''
        by = Dict({
            'id': By.ID,
            'name': By.NAME,
            'xpath': By.XPATH,
            'class': By.CLASS_NAME,
            'tag_name': By.TAG_NAME,
            'link_text': By.LINK_TEXT,
            'css_selector': By.CSS_SELECTOR,
            'partial_link_text': By.PARTIAL_LINK_TEXT,
        })
'''
element_id = find_element(By.ID, 'su')
```

#### 获取多个元素($.getElement)

`$.getElement` 获取单个元素，参数: `element`   

```yaml
# 获取多个元素 id|name|class|tag_name|link_text|partial_link_text|xpath|css_selector
- ${elements_class} = $.getElements('class=title-content-title')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
elements_class = find_elements(By.CLASS_NAME, 'title-content-title')
```

#### 判断元素是否选中($.isSelected)

`$.isSelected` 判断元素是否选中，参数: `element`   

```yaml
- ${element_id} = $.getElement('id=su')
- ${is_selected} = $.isSelected(${element_id})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
is_selected = element_id.is_selected()
```

#### 判断元素是否显示($.isDisplayed)

`$.isDisplayed` 判断元素是否显示，参数: `element`   

```yaml
- ${element_id} = $.getElement('id=su')
- ${is_displayed} = $.isDisplayed(${element_id})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
is_displayed = .is_displayed()
```

#### 判断元素是否可用($.isEnabled)

`$.isEnabled` 判断元素是否可用，参数: `element`   

```yaml
- ${element_id} = $.getElement('id=su')
- ${is_enabled} = $.isEnabled(${element_id})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
is_enabled = element_id.is_enabled()
```

#### 获取元素大小($.getSize)

`$.getSize` 判断元素是否选中，参数: `element`   

```yaml
- ${element_id} = $.getElement('id=su')
- ${size} = $.getSize(${element_id})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
size = element_id.size
```

#### 获取元素坐标($.getLocation)

`$.getLocation` 获取元素坐标，参数: `element`   

```yaml
- ${element_id} = $.getElement('id=su')
- ${location} = $.getLocation(${element_id})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
location = element_id.location
```

#### 获取元素位置大小($.getRect)

`$.getRect` 获取元素位置大小，参数: `element`   

```yaml
- ${element_id} = $.getElement('id=su')
- ${rect} = $.getRect(${element_id})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
rect = element_id.rect
```

#### 获取元素标签($.getTagName)

`$.getTagName` 获取元素标签，参数: `element`   

```yaml
- ${element_id} = $.getElement('id=su')
- ${tag} = $.getTagName(${element_id})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
tag = element_id.tag_name
```

#### 获取元素文案($.getText)

`$.getText` 获取元素位置文案，参数: `element`   

```yaml
- ${element_id} = $.getElement('id=su')
- ${text} = $.getText(${element_id})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
text = element_id.text
```

#### 获取元素属性($.getAttribute)

`$.getAttribute` 获取元素位置属性，参数: `element` ， `attribute` 

```yaml
- ${element_id} = $.getElement('id=su')
- ${attribute} = $.getAttribute(${element_id}, 'value')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
attribute = element.get_attribute('value')
```

#### 获取元素CSS($.getCssProperty)

`$.getCssProperty` 获取元素CSS，参数: `element` ， `css` 

```yaml
- ${element_id} = $.getElement('id=su')
- ${css} = $.getCssProperty(${element_id}, 'height')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
element_id = find_element(By.ID, 'su')
css = element_id.value_of_css_property('height')
```

### 

### Cookie

#### 获取所有Cookie($.getCookies)

`$.getCookies` 获取所有Cookie

```yaml
- ${cookies} = $.getCookies()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
cookies = driver.get_cookies()
```

#### 获取指定Cookie($.getCookie)

`$.getCookie` 获取指定Cookie，参数: `name`

```yaml
- ${cookie} = $.getCookie('BAIDUID')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
cookie = driver.get_cookie('BAIDUID')
```

#### 删除指定Cookie(deleteCookie)

`deleteCookie` 删除指定Cookie，参数: `name`

```yaml
- deleteCookie('BAIDUID')
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.delete_cookie('BAIDUID')
```

#### 删除所有Cookie(_deleteAllCookies_)

`deleteAllCookies` 删除所有Cookie

```yaml
- deleteAllCookies()
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
driver.delete_all_cookies()
```

#### 添加指定Cookie(addCookie)

`addCookie` 添加指定Cookie，参数: `cookie`

```yaml
- ${add_cookie} = {'name':'ADDCOOKIE','value':'123adc'}
- addCookie(${add_cookie})
```

对应Selenium API：

```python
driver = webdriver.Chrome()
driver.get(url)
add_cookie = {'name':'ADDCOOKIE','value':'123adc'}
driver.add_cookie(add_cookie)
```


## Other Action

### **变量(**${variables}**)**

关于变量已经在开头介绍过，这里演示变量几种写法

```yaml
# 直接赋值
- ${t1} = 1
- ${t2} = '2'
- ${t3} = "3"
- ${t4} = True
- ${t5} = False
- ${t6} = None
- ${t7} = [1,2,3]
- ${t8} = {'key':'value'}
# 调用方法返回
- ${elements} = $.getElements('class=title-content-title')
```

如果变量值为列表或字典，可以指定index或者key来获取其中某一个元素的值

```yaml
- keyDown(${7}[0], ${t8}['key'])
```

### 设置全局变量(setVar)**

`setVar` 设置全局变量，该变量在整个测试执行结束后才会销毁，参数： `key` ， `value` 

```yaml
- setVar('key','测试')
```

### 获取全局变量($.getVar)**

`$.getVar` 获取全局变量，参数： `key`

```yaml
- ${test} = $.getVar('key')
```

### 获取长度($.getLen)

`$.getLen` 可以获取其他变量的长度，这对于循环是有帮助的，参数： `variables` 

```yaml
- ${t7} = [1,2,3]
- ${len} = $.getLen(${t7})
```

### 睡眠(sleep)

`sleep` 在当前步骤等待指定时间，参数： `s` 

```yaml
- sleep(5) # 等待5s
```

### 断言(assert)

`assert` 用例中可以直接断言来检查执行是否符合预期效果，参数：`条件表达式` 

```yaml
- assert 5 > 4
- ${text} = '测试文案'
- assert '文案' == ${text}
- assert '文案' in '测试文案'
```

### 执行表达式($.id)

`$.id` 用于执行一个表达式，参数：`表达式`

```yaml
- ${index} = $.id(1+1) # 2
- ${str} = $.id('测试'+'文案') # 测试文案
```

### 条件语句(if、elif、else)

`if` 、 `elif` 、 `else` 根据条件表达式来决定执行代码，参数：`条件表达式`

```yaml
- ${index} = $.id(1+1) # 2
- if ${index} == 2:
    - ${test} = 1
  elif ${index} > 2:
    - ${test} = 2
  else:
    - ${test} = 3
```

### 循环语句(while)

`while` 用于循环执行程序， 参数：`条件表达式`
`break` 在某一条件成立时，可以跳出循环

```yaml
- ${list} = [1,2,3,4]
- ${len} = $.getLen(${list})
- while ${len}:
    - ${len} = $.id(${len}-1)
    - if ${list}[${len}] == 2:
      - break
```

### 循环语句(for)

`for` 循环可以遍历任何序列的项目，如一个列表或者一个字符串， 参数： `可迭代对象` 
`break` 在某一条件成立时，可以跳出循环

```yaml
# 打开URL
- openUrl('https://www.baidu.com')
# 打开一个新窗口  
- click('xpath=//*[@id="s-top-left"]/a[1]')
# 获取所有窗口句柄
- ${all_handle} = $.getWindowHandles()
# for 循环
- for ${handle} in ${all_handle}:
    # 切换窗口句柄
    - switchToWindow(${handle})
    - ${title} = $.getTitle()
    - if ${title} == '百度新闻——海量中文资讯平台':
        - break
```

# End