基于 skill-template 脚手架开发,包含: - payroll_config(费率配置,可编辑)+ payslip_snapshots(解析历史,只读)2 张业务表 - 全国默认 + 北上广 4 套费率(社保/公积金/个税起征点/7 级税率表) - 5 个业务 Action:calculate-payslip-simple / calculate-payslip-full / explain-term / view-config / edit-config - 个税累计预扣法计算,支持多月历史累加 - 20 个薪资名词库(社保/公积金/个税/全勤/加班费等) - 完整市场文档(README/TUTORIAL/DEMO/CHANGELOG) - 296 测试全部通过
100 lines
3.9 KiB
Python
100 lines
3.9 KiB
Python
from __future__ import annotations
|
|
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT / "scripts"))
|
|
|
|
from service.desktop_session import ( # noqa: E402
|
|
DesktopRpaError,
|
|
WindowCandidate,
|
|
activate_window,
|
|
resolve_unique_window,
|
|
)
|
|
from service import uia_locator # noqa: E402
|
|
from util.selectors import ElementSpec, MAIN_WINDOW # noqa: E402
|
|
|
|
|
|
class SelectorContractTest(unittest.TestCase):
|
|
def test_unique_window_is_required(self) -> None:
|
|
candidate = WindowCandidate(1, 10, "WXWork", "WeWorkWindow", "企业微信", True)
|
|
self.assertEqual(
|
|
resolve_unique_window(MAIN_WINDOW, candidates=[candidate]),
|
|
candidate,
|
|
)
|
|
|
|
def test_duplicate_windows_fail_instead_of_taking_first(self) -> None:
|
|
candidates = [
|
|
WindowCandidate(1, 10, "WXWork", "WeWorkWindow", "企业微信", True),
|
|
WindowCandidate(2, 11, "WXWork", "WeWorkWindow", "企业微信", True),
|
|
]
|
|
with self.assertRaises(DesktopRpaError) as ctx:
|
|
resolve_unique_window(MAIN_WINDOW, candidates=candidates)
|
|
self.assertEqual(ctx.exception.code, "ELEMENT_AMBIGUOUS")
|
|
|
|
def test_hidden_window_is_not_a_candidate(self) -> None:
|
|
hidden = WindowCandidate(1, 10, "WXWork", "WeWorkWindow", "企业微信", False)
|
|
with self.assertRaises(DesktopRpaError) as ctx:
|
|
resolve_unique_window(MAIN_WINDOW, candidates=[hidden])
|
|
self.assertEqual(ctx.exception.code, "WINDOW_NOT_FOUND")
|
|
|
|
def test_activate_without_maximize_skips_restore_when_zoomed(self) -> None:
|
|
window = WindowCandidate(42, 10, "WXWork", "WeWorkWindow", "企业微信", True)
|
|
with patch("service.desktop_session.user32") as user32:
|
|
user32.IsIconic.return_value = False
|
|
user32.IsZoomed.return_value = True
|
|
user32.SetForegroundWindow.return_value = True
|
|
activate_window(window, maximize=False)
|
|
user32.ShowWindow.assert_not_called()
|
|
user32.SetForegroundWindow.assert_called_once_with(42)
|
|
|
|
def test_activate_maximize_when_not_zoomed(self) -> None:
|
|
window = WindowCandidate(42, 10, "WXWork", "WeWorkWindow", "企业微信", True)
|
|
with patch("service.desktop_session.user32") as user32:
|
|
user32.IsIconic.return_value = False
|
|
user32.IsZoomed.return_value = False
|
|
user32.SetForegroundWindow.return_value = True
|
|
activate_window(window, maximize=True)
|
|
user32.ShowWindow.assert_called()
|
|
user32.SetForegroundWindow.assert_called_once_with(42)
|
|
|
|
def test_locate_unique_matches_child_value(self) -> None:
|
|
row = MagicMock()
|
|
row.Name = "status_layout"
|
|
row.AutomationId = ""
|
|
row.ControlTypeName = "TreeControl"
|
|
row.ClassName = ""
|
|
label = MagicMock()
|
|
label.Name = "main_chattext"
|
|
label.GetChildren.return_value = []
|
|
row.GetChildren.return_value = [label]
|
|
|
|
root = MagicMock()
|
|
root.Name = "wlist_view"
|
|
root.AutomationId = ""
|
|
root.ControlTypeName = "TreeControl"
|
|
root.ClassName = ""
|
|
root.GetChildren.return_value = [row]
|
|
|
|
with patch.object(uia_locator, "control_value", side_effect=lambda c: "新的客户" if c is label else ""):
|
|
spec = ElementSpec(
|
|
"new_customer_row",
|
|
name="status_layout",
|
|
ancestor_name="wlist_view",
|
|
child_value_name="main_chattext",
|
|
value="新的客户",
|
|
)
|
|
# ancestor is root itself when searching from root with name wlist_view
|
|
found = uia_locator.locate_unique(root, ElementSpec("wlist", name="wlist_view"))
|
|
self.assertIs(found, root)
|
|
found_row = uia_locator.locate_unique(root, spec)
|
|
self.assertIs(found_row, row)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|