Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add xpath tests, remove logzero, add enable_pretty_logging #950

Merged
merged 2 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ exclude_also =

ignore_errors = True

[paths]
source =
uiautomator2/

omit =
"tests/*"
"docs/*"
23 changes: 20 additions & 3 deletions docs/2to3.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,27 @@

- 版本管理从pbr改为poetry,同时降低依赖库的数量
- Python依赖调整为最低3.8
- 增加更多的单测代码,让项目变的更稳定
- 移除一些陈年老代码
- 增加更多的单测
- minicap,minitouch不再默认安装

# 增加
开启库的详细日志的方法

```python
from uiautomator2 import enable_pretty_logging
enable_pretty_logging()
```

## 移除的功能
- current_app函数移除
- `d.xpath("...").wait()`从原有的返回 XMLElement|None,改为返回 bool
- `d.xpath("...").wait()`从原有的返回 XMLElement|None,改为返回 bool
- 日志库清理
- 移除 logzero依赖
- 移除 property u2.logger
- 移除 property u2.xpath.XPath.logger
- 移除 property d.watcher.debug
- 移除 d.settings["xpath_debug"]
- 移除 function XPath.apply_watch_from_yaml
- connect_usb函数中的init参数移除,这个参数目前没什么用了

TODO: atx-agent不在依赖外网下载,直接打包到内部
56 changes: 0 additions & 56 deletions examples/com.netease.cloudmusic/xpath_test.py

This file was deleted.

6 changes: 5 additions & 1 deletion examples/runyaml/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#

import argparse
import logging
import os
import re
import time
Expand All @@ -13,6 +14,7 @@

import uiautomator2 as u2


CLICK = "click"
# swipe
SWIPE_UP = "swipe_up"
Expand Down Expand Up @@ -52,7 +54,9 @@ def read_file_content(path: str, mode:str = "r") -> str:
def run_step(cf: bunch.Bunch, app: u2.Session, step: str):
logger.info("Step: %s", step)
oper, body = split_step(step)
logger.debug("parse as: %s %s", oper, body)
logger

logger = logging.getLogger(__name__).debug("parse as: %s %s", oper, body)

if oper == CLICK:
app.xpath(body).click()
Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@ include = ["*/assets/*.apk"]
python = "^3.8"
requests = "*"
lxml = "*"
adbutils = ">=2.2"
adbutils = "^2.2.3"
retry = ">=0,<1"
packaging = ">=20.3"
pillow = "*"

# TODO: remove later
Deprecated = "*"
logzero = "*"
filelock = ">=3,<4"
progress = "^1.6"
pillow = "*"

[tool.poetry.group.dev.dependencies]
pytest = "^8.1.1"
Expand Down
25 changes: 25 additions & 0 deletions tests/unittests/test_logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Created on Thu Apr 04 2024 16:57:34 by codeskyblue
"""

import logging
import pytest
from uiautomator2 import enable_pretty_logging


def test_enable_pretty_logging(caplog: pytest.LogCaptureFixture):
logger = logging.getLogger("uiautomator2")

logger.info("should not be printed")
enable_pretty_logging()
logger.info("hello")
enable_pretty_logging(logging.INFO)
logger.info("world")
logger.debug("should not be printed")

# Use caplog.text to check the entire log output as a single string
assert "hello" in caplog.text
assert "world" in caplog.text
assert "should not be printed" not in caplog.text
83 changes: 83 additions & 0 deletions tests/unittests/test_xpath.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Created on Thu Apr 04 2024 16:41:25 by codeskyblue
"""

import pytest
from unittest.mock import Mock
from PIL import Image
from uiautomator2.xpath import XMLElement, XPathSelector, XPath, XPathElementNotFoundError


mock = Mock()
mock.screenshot.return_value = Image.new("RGB", (1080, 1920), "white")
mock.dump_hierarchy.return_value = """<?xml version="1.0" encoding="UTF-8"?>
<hierarchy rotation="0">
<node index="0" text="" resource-id="android:id/content" class="FrameLayout" content-desc="" bounds="[0,0][1080,1920]">
<node index="0" text="n1" resource-id="android:id/text1" class="TextView" content-desc="" bounds="[0,0][1080,100]" />
<node index="1" text="n2" resource-id="android:id/text2" class="TextView" content-desc="" bounds="[0,100][1080,200]" />
</node>
<node index="1" text="" resource-id="android:id/statusBarBackground" class="android.view.View" package="com.android.systemui" content-desc="" bounds="[0,0][1080,24]" />
</hierarchy>
"""

x = XPath(mock)

def test_xpath_click():
x("n1").click()
assert mock.click.called
assert mock.click.call_args[0] == (540, 50)

mock.click.reset_mock()
assert x("n1").click_exists() == True
assert mock.click.call_args[0] == (540, 50)

mock.click.reset_mock()
assert x("n3").click_exists(timeout=.1) == False
assert not mock.click.called


def test_xpath_exists():
assert x("n1").exists
assert not x("n3").exists


def test_xpath_wait_and_wait_gone():
assert x("n1").wait() is True
assert x("n3").wait(timeout=.1) is False

assert x("n3").wait_gone(timeout=.1) is True
assert x("n1").wait_gone(timeout=.1) is False


def test_xpath_get():
assert x("n1").get().text == "n1"
assert x("n2").get().text == "n2"

with pytest.raises(XPathElementNotFoundError):
x("n3").get(timeout=.1)


def test_xpath_all():
assert len(x("//TextView").all()) == 2
assert len(x("n3").all()) == 0

assert len(x("n1").all()) == 1
el = x("n1").all()[0]
assert isinstance(el, XMLElement)
assert el.text == "n1"


def test_xpath_element():
el = x("n1").get(timeout=0)
assert el.text == "n1"
assert el.center() == (540, 50)
assert el.screenshot().size == (1080, 100)
assert el.bounds == (0, 0, 1080, 100)
assert el.get_xpath() == "/hierarchy/FrameLayout/TextView[1]"

mock.click.reset_mock()
el.click()
assert mock.click.called
assert mock.click.call_args[0] == (540, 50)
Loading